sql数据流,amdin业务逻辑接入
This commit is contained in:
@@ -69,21 +69,72 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { fetchMemberConfig, saveMemberConfig, MemberConfig } from '@/services/admin/marketingService.uts'
|
||||
|
||||
const isSaving = ref(false)
|
||||
|
||||
const config = reactive({
|
||||
is_open: true,
|
||||
bg_img: 'https://demo26.crmeb.net/uploads/attach/2021/11/20211115/a6f3b06e9d6d5a1b3c9d6d5a1b3c9d6d.png',
|
||||
bg_img: '',
|
||||
expire_bg_img: '',
|
||||
rules: '1. 会员有效期自购买之日起计算\n2. 会员权益仅限本人使用\n3. 会员卡一经售出,概不退换'
|
||||
rules: ''
|
||||
})
|
||||
|
||||
const handleUpload = (type: string) => {
|
||||
uni.showToast({ title: '文件管理器暂未开启', icon: 'none' })
|
||||
onMounted(() => {
|
||||
loadConfig()
|
||||
})
|
||||
|
||||
async function loadConfig() {
|
||||
try {
|
||||
const res = await fetchMemberConfig()
|
||||
if (res != null) {
|
||||
config.is_open = res.is_enabled
|
||||
config.bg_img = res.bg_img_url ?? ''
|
||||
config.expire_bg_img = res.expire_bg_img_url ?? ''
|
||||
config.rules = res.rules_description ?? ''
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '加载配置失败', icon: 'none' })
|
||||
}
|
||||
}
|
||||
|
||||
const handleSave = () => {
|
||||
uni.showToast({ title: '保存成功', icon: 'success' })
|
||||
const handleUpload = (type: string) => {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
success: (res) => {
|
||||
if (type === 'bg') {
|
||||
config.bg_img = res.tempFilePaths[0]
|
||||
} else {
|
||||
config.expire_bg_img = res.tempFilePaths[0]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
if (isSaving.value) return
|
||||
|
||||
isSaving.value = true
|
||||
const payload : MemberConfig = {
|
||||
is_enabled: config.is_open,
|
||||
bg_img_url: config.bg_img,
|
||||
expire_bg_img_url: config.expire_bg_img,
|
||||
rules_description: config.rules
|
||||
}
|
||||
|
||||
try {
|
||||
const success = await saveMemberConfig(payload)
|
||||
if (success) {
|
||||
uni.showToast({ title: '保存成功', icon: 'success' })
|
||||
} else {
|
||||
uni.showToast({ title: '保存失败', icon: 'none' })
|
||||
}
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '系统异常', icon: 'none' })
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
<view class="marketing-member-right">
|
||||
<view class="table-card border-shadow">
|
||||
<view class="table-container">
|
||||
<!-- Loading 遮罩 -->
|
||||
<view v-if="isLoading" class="loading-mask">
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view class="table-head">
|
||||
<view class="th cell-id">ID</view>
|
||||
<view class="th cell-icon">权益图标</view>
|
||||
@@ -13,20 +18,23 @@
|
||||
</view>
|
||||
|
||||
<view class="table-body">
|
||||
<view v-if="memberRights.length === 0 && !isLoading" class="empty-row">
|
||||
<text>暂无权益配置</text>
|
||||
</view>
|
||||
<view v-for="item in memberRights" :key="item.id" class="table-row">
|
||||
<view class="td cell-id"><text class="td-txt">{{ item.id }}</text></view>
|
||||
<view class="td cell-icon">
|
||||
<image class="right-icon" :src="item.icon" mode="aspectFit"></image>
|
||||
<image class="right-icon" :src="item.icon_url || '/static/logo.png'" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="td cell-name"><text class="td-txt">{{ item.name }}</text></view>
|
||||
<view class="td cell-desc"><text class="td-txt">{{ item.desc }}</text></view>
|
||||
<view class="td cell-desc"><text class="td-txt">{{ item.description || '-' }}</text></view>
|
||||
<view class="td cell-status">
|
||||
<view class="switch-mock" :class="{ active: item.is_show }" @click="toggleStatus(item)">
|
||||
<view class="switch-dot"></view>
|
||||
<text class="switch-txt">{{ item.is_show ? '显示' : '隐藏' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="td cell-sort"><text class="td-txt">{{ item.sort }}</text></view>
|
||||
<view class="td cell-sort"><text class="td-txt">{{ item.sort_order }}</text></view>
|
||||
<view class="td cell-op">
|
||||
<text class="op-link" @click="handleEdit(item)">编辑</text>
|
||||
</view>
|
||||
@@ -38,20 +46,39 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { fetchMemberRights, saveMemberRight, MemberRight } from '@/services/admin/marketingService.uts'
|
||||
|
||||
const memberRights = ref([
|
||||
{ id: 9, icon: 'https://demo26.crmeb.net/uploads/attach/2021/11/20211115/a6f3b06e9d6d5a1b3c9d6d5a1b3c9d6d.png', name: '运费券', desc: '每月领取运费券', is_show: true, sort: 10 },
|
||||
{ id: 8, icon: 'https://demo26.crmeb.net/uploads/attach/2021/11/20211115/a6f3b06e9d6d5a1b3c9d6d5a1b3c9d6d.png', name: '充值优惠', desc: '充值立减优惠', is_show: true, sort: 8 },
|
||||
{ id: 7, icon: 'https://demo26.crmeb.net/uploads/attach/2021/11/20211115/a6f3b06e9d6d5a1b3c9d6d5a1b3c9d6d.png', name: '积分翻倍', desc: '购物获取双倍积分', is_show: true, sort: 7 }
|
||||
])
|
||||
const memberRights = ref<MemberRight[]>([])
|
||||
const isLoading = ref(false)
|
||||
|
||||
const toggleStatus = (item: any) => {
|
||||
item.is_show = !item.is_show
|
||||
uni.showToast({ title: '修改成功', icon: 'success' })
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
|
||||
async function loadData() {
|
||||
isLoading.value = true
|
||||
try {
|
||||
const res = await fetchMemberRights()
|
||||
memberRights.value = res
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleEdit = (item: any) => {
|
||||
async function toggleStatus(item : MemberRight) {
|
||||
if (item.id == null) return
|
||||
const nextStatus = !item.is_show
|
||||
const success = await saveMemberRight({ ...item, is_show: nextStatus } as MemberRight)
|
||||
if (success) {
|
||||
item.is_show = nextStatus
|
||||
uni.showToast({ title: '修改成功', icon: 'success' })
|
||||
}
|
||||
}
|
||||
|
||||
const handleEdit = (item: MemberRight) => {
|
||||
uni.showToast({ title: '编辑功能开发中', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
@@ -136,6 +163,31 @@ const handleEdit = (item: any) => {
|
||||
.switch-mock.active .switch-txt { margin-left: 4px; }
|
||||
|
||||
.op-link { color: #1890ff; font-size: 13px; cursor: pointer; }
|
||||
|
||||
/* Loading & Empty Styles */
|
||||
.table-container {
|
||||
position: relative;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.loading-mask {
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.loading-text { color: #1890ff; font-size: 14px; }
|
||||
|
||||
.empty-row {
|
||||
padding: 60px 0;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
@@ -13,22 +13,44 @@
|
||||
<view class="th cell-op">操作</view>
|
||||
</view>
|
||||
|
||||
<view class="table-body">
|
||||
<view v-for="item in memberTypes" :key="item.id" class="table-row">
|
||||
<view class="td cell-id"><text class="td-txt">{{ item.id }}</text></view>
|
||||
<view class="td cell-name"><text class="td-txt">{{ item.name }}</text></view>
|
||||
<view class="td cell-days"><text class="td-txt">{{ item.days }}</text></view>
|
||||
<view class="td cell-price"><text class="td-txt">¥{{ item.price.toFixed(2) }}</text></view>
|
||||
<view class="td cell-discount"><text class="td-txt">¥{{ item.discount.toFixed(2) }}</text></view>
|
||||
<view class="td cell-status">
|
||||
<view class="switch-mock" :class="{ active: item.is_open }" @click="toggleStatus(item)">
|
||||
<view class="switch-dot"></view>
|
||||
<text class="switch-txt">{{ item.is_open ? '开启' : '关闭' }}</text>
|
||||
</view>
|
||||
<!-- 表格主体 -->
|
||||
<view class="table-container">
|
||||
<!-- Loading 遮罩 -->
|
||||
<view v-if="isLoading" class="loading-mask">
|
||||
<text class="loading-text">数据加载中...</text>
|
||||
</view>
|
||||
|
||||
<view class="table-header">
|
||||
<view class="th cell-id">ID</view>
|
||||
<view class="th cell-name">会员名</view>
|
||||
<view class="th cell-days">有效期(天)</view>
|
||||
<view class="th cell-price">原价</view>
|
||||
<view class="th cell-discount">优惠价</view>
|
||||
<view class="th cell-status">是否开启</view>
|
||||
<view class="th cell-sort">排序</view>
|
||||
<view class="th cell-op">操作</view>
|
||||
</view>
|
||||
|
||||
<view class="table-body">
|
||||
<view v-if="memberTypes.length === 0 && !isLoading" class="empty-row">
|
||||
<text>暂无会员类型配置</text>
|
||||
</view>
|
||||
<view class="td cell-sort"><text class="td-txt">{{ item.sort }}</text></view>
|
||||
<view class="td cell-op">
|
||||
<text class="op-link" @click="handleEdit(item)">编辑</text>
|
||||
<view v-for="item in memberTypes" :key="item.id" class="table-row">
|
||||
<view class="td cell-id"><text class="td-txt">{{ item.id }}</text></view>
|
||||
<view class="td cell-name"><text class="td-txt">{{ item.name }}</text></view>
|
||||
<view class="td cell-days"><text class="td-txt">{{ item.duration_days == 0 ? '永久' : item.duration_days }}</text></view>
|
||||
<view class="td cell-price"><text class="td-txt">¥{{ item.price.toFixed(2) }}</text></view>
|
||||
<view class="td cell-discount"><text class="td-txt">¥{{ item.discount_price.toFixed(2) }}</text></view>
|
||||
<view class="td cell-status">
|
||||
<view class="switch-mock" :class="{ active: item.is_open }" @click="toggleStatus(item)">
|
||||
<view class="switch-dot"></view>
|
||||
<text class="switch-txt">{{ item.is_open ? '开启' : '关闭' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="td cell-sort"><text class="td-txt">{{ item.sort_order }}</text></view>
|
||||
<view class="td cell-op">
|
||||
<text class="op-link" @click="handleEdit(item)">编辑</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -38,22 +60,39 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { fetchMemberTypes, saveMemberType, MemberType } from '@/services/admin/marketingService.uts'
|
||||
|
||||
const memberTypes = ref([
|
||||
{ id: 5, name: '44555', days: '12', price: 69.00, discount: 0.00, is_open: true, sort: 55 },
|
||||
{ id: 4, name: '5566', days: '永久', price: 1080.00, discount: 1080.00, is_open: true, sort: 5 },
|
||||
{ id: 3, name: '年卡', days: '365', price: 99.00, discount: 0.01, is_open: true, sort: 5 },
|
||||
{ id: 2, name: '55', days: '90', price: 699.00, discount: 499.00, is_open: true, sort: 5 },
|
||||
{ id: 1, name: '55', days: '30', price: 699.00, discount: 499.00, is_open: true, sort: 5 }
|
||||
])
|
||||
const memberTypes = ref<MemberType[]>([])
|
||||
const isLoading = ref(false)
|
||||
|
||||
const toggleStatus = (item: any) => {
|
||||
item.is_open = !item.is_open
|
||||
uni.showToast({ title: '修改成功', icon: 'success' })
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
|
||||
async function loadData() {
|
||||
isLoading.value = true
|
||||
try {
|
||||
const res = await fetchMemberTypes()
|
||||
memberTypes.value = res
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleEdit = (item: any) => {
|
||||
async function toggleStatus(item : MemberType) {
|
||||
if (item.id == null) return
|
||||
const nextStatus = !item.is_open
|
||||
const success = await saveMemberType({ ...item, is_open: nextStatus } as MemberType)
|
||||
if (success) {
|
||||
item.is_open = nextStatus
|
||||
uni.showToast({ title: '修改成功', icon: 'success' })
|
||||
}
|
||||
}
|
||||
|
||||
const handleEdit = (item: MemberType) => {
|
||||
uni.showToast({ title: '编辑功能开发中', icon: 'none' })
|
||||
}
|
||||
</script>
|
||||
@@ -141,6 +180,30 @@ const handleEdit = (item: any) => {
|
||||
|
||||
.op-link { color: #1890ff; font-size: 13px; cursor: pointer; }
|
||||
|
||||
/* Loading & Empty Styles */
|
||||
.table-container {
|
||||
position: relative;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.loading-mask {
|
||||
position: absolute;
|
||||
top: 0; left: 0; right: 0; bottom: 0;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.loading-text { color: #1890ff; font-size: 14px; }
|
||||
|
||||
.empty-row {
|
||||
padding: 60px 0;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user