admin模块接入数据库

This commit is contained in:
comlibmb
2026-02-13 17:29:50 +08:00
parent 56209b7a75
commit ec636dc703
58 changed files with 5586 additions and 1394 deletions

View File

@@ -68,26 +68,32 @@
</view>
<view class="table-body">
<view v-for="(item, index) in dataList" :key="item.id" class="table-row">
<view class="td" style="width: 80px;"><text class="td-txt">{{ item.id }}</text></view>
<view v-if="isLoading" class="table-loading" style="padding: 40px; text-align: center;">
<text>数据加载中...</text>
</view>
<view v-else-if="dataList.length === 0" class="table-empty" style="padding: 40px; text-align: center;">
<text>暂无优惠券数据</text>
</view>
<view v-else v-for="(item, index) in dataList" :key="item.id" class="table-row">
<view class="td" style="width: 80px;"><text class="td-txt">{{ item.cid || '-' }}</text></view>
<view class="td" style="width: 180px;"><text class="td-txt name-bold">{{ item.name }}</text></view>
<view class="td" style="width: 120px;"><text class="td-txt">{{ item.type }}</text></view>
<view class="td" style="width: 100px;"><text class="td-txt price-txt">{{ item.value.toFixed(2) }}</text></view>
<view class="td" style="width: 120px;"><text class="td-txt">{{ item.receiveType }}</text></view>
<view class="td" style="width: 150px;">
<text v-if="item.id === 1628" class="td-txt date-small">2023-10-18 00:00 - 2025-11-05 00:00</text>
<text v-else class="td-txt">{{ item.receiveDate }}</text>
<view class="td" style="width: 120px;"><text class="td-txt">{{ getTypeName(item.coupon_type) }}</text></view>
<view class="td" style="width: 100px;">
<text class="td-txt price-txt">{{ item.discount_value }}{{ item.discount_type === 2 ? '%' : '元' }}</text>
</view>
<view class="td" style="width: 120px;"><text class="td-txt">{{ item.useTime }}</text></view>
<view class="td" style="width: 120px;"><text class="td-txt">{{ getReceiveTypeName(1) }}</text></view>
<view class="td" style="width: 150px;">
<text class="td-txt date-small">{{ formatTime(item.start_time) }} 至 {{ formatTime(item.end_time) }}</text>
</view>
<view class="td" style="width: 120px;"><text class="td-txt">{{ item.usage_limit }} 次/人</text></view>
<view class="td" style="width: 120px;">
<view v-if="item.publishTotal > 0" class="pub-info">
<text class="pub-txt">发布: {{ item.publishTotal }}</text>
<text class="pub-txt danger">剩余: {{ item.publishRemain }}</text>
<view v-if="item.total_quantity != null && item.total_quantity > 0" class="pub-info">
<text class="pub-txt">总计: {{ item.total_quantity }}</text>
</view>
<text v-else class="td-txt">不限量</text>
</view>
<view class="td" style="width: 100px;">
<view :class="['switch-box', item.isOpen ? 'active' : '']" @click="toggleStatus(index)">
<view :class="['switch-box', item.status === 1 ? 'active' : '']" @click="toggleStatus(index)">
<view class="switch-dot"></view>
</view>
</view>
@@ -97,9 +103,7 @@
<text class="op-split">|</text>
<text class="op-link">编辑</text>
<text class="op-split">|</text>
<text class="op-link">复制</text>
<text class="op-split">|</text>
<text class="op-link text-danger">删除</text>
<text class="op-link" @click="handleDelete(item.id)">删除</text>
</view>
</view>
</view>
@@ -108,20 +112,11 @@
<!-- 分页 -->
<view class="pagination-footer">
<text class="total-txt">共 16 条</text>
<view class="page-select">
<text class="page-val">15条/页 ▼</text>
</view>
<text class="total-txt">共 {{ total }} 条</text>
<view class="page-btns">
<text class="p-btn disabled"><</text>
<text class="p-btn active">1</text>
<text class="p-btn">2</text>
<text class="p-btn">></text>
</view>
<view class="page-jump">
<text class="jump-txt">前往</text>
<input class="jump-input" placeholder="1" />
<text class="jump-txt">页</text>
<text :class="['p-btn', page <= 1 ? 'disabled' : '']" @click="prevPage"><</text>
<text class="p-btn active">{{ page }}</text>
<text :class="['p-btn', page >= totalPages ? 'disabled' : '']" @click="nextPage">></text>
</view>
</view>
</view>
@@ -130,44 +125,145 @@
</template>
<script setup lang="uts">
import { ref, reactive } from 'vue'
interface CouponItem {
id: number
name: string
type: string
value: number
receiveType: string
receiveDate: string
useTime: string
publishTotal: number
publishRemain: number
isOpen: boolean
}
import { ref, reactive, onMounted, computed } from 'vue'
import {
fetchAdminCoupons,
toggleCouponStatus,
deleteCouponTemplate,
CouponTemplate,
CouponQuery
} from '@/services/admin/marketingService.uts'
const filter = reactive({
name: ''
name: '',
type: null as number | null,
status: null as number | null
})
const dataList = ref<CouponItem[]>([
{ id: 1643, name: '满100减30', type: '通用券', value: 30.00, receiveType: '用户领取', receiveDate: '不限时', useTime: '10天', publishTotal: 0, publishRemain: 0, isOpen: false },
{ id: 1642, name: '满10减7', type: '通用券', value: 7.00, receiveType: '用户领取', receiveDate: '不限时', useTime: '10天', publishTotal: 0, publishRemain: 0, isOpen: true },
{ id: 1641, name: '会员优惠券', type: '通用券', value: 200.00, receiveType: '用户领取', receiveDate: '不限时', useTime: '200天', publishTotal: 0, publishRemain: 0, isOpen: true },
{ id: 1640, name: '会员优惠券', type: '通用券', value: 29.90, receiveType: '用户领取', receiveDate: '不限时', useTime: '200天', publishTotal: 0, publishRemain: 0, isOpen: true },
{ id: 1639, name: '会员优惠券', type: '通用券', value: 1.00, receiveType: '用户领取', receiveDate: '不限时', useTime: '200天', publishTotal: 0, publishRemain: 0, isOpen: true },
{ id: 1638, name: '商品券', type: '商品券', value: 1.00, receiveType: '用户领取', receiveDate: '不限时', useTime: '200天', publishTotal: 0, publishRemain: 0, isOpen: true },
{ id: 1636, name: '测试多个商品消耗一个券', type: '商品券', value: 500.00, receiveType: '系统赠送', receiveDate: '不限时', useTime: '3天', publishTotal: 0, publishRemain: 0, isOpen: true },
{ id: 1635, name: '优惠券', type: '通用券', value: 10.00, receiveType: '系统赠送', receiveDate: '不限时', useTime: '10天', publishTotal: 0, publishRemain: 0, isOpen: true },
{ id: 1634, name: '限时优惠', type: '通用券', value: 20.00, receiveType: '用户领取', receiveDate: '不限时', useTime: '5天', publishTotal: 0, publishRemain: 0, isOpen: true },
{ id: 1633, name: '店庆券', type: '品类券', value: 100.00, receiveType: '用户领取', receiveDate: '不限时', useTime: '10天', publishTotal: 0, publishRemain: 0, isOpen: true },
{ id: 1632, name: '优惠券', type: '品类券', value: 99.00, receiveType: '用户领取', receiveDate: '不限时', useTime: '10天', publishTotal: 8999, publishRemain: 8604, isOpen: true },
{ id: 1628, name: '全场通用券', type: '通用券', value: 9.90, receiveType: '用户领取', receiveDate: 'RANGE', useTime: '不限时', publishTotal: 59999, publishRemain: 59331, isOpen: true }
])
const dataList = ref<CouponTemplate[]>([])
const total = ref(0)
const isLoading = ref(false)
const page = ref(1)
const pageSize = 15
const handleQuery = () => { console.log('Querying...') }
const handleAdd = () => { console.log('Adding coupon...') }
const toggleStatus = (index: number) => {
dataList.value[index].isOpen = !dataList.value[index].isOpen
const typeOptions = [
{ label: '全部', value: null },
{ label: '满减券', value: 1 },
{ label: '折扣券', value: 2 },
{ label: '免运费券', value: 3 }
]
const typeIndex = ref(0)
const statusOptions = [
{ label: '全部', value: null },
{ label: '开启', value: 1 },
{ label: '关闭', value: 2 },
{ label: '已结束', value: 3 }
]
const statusIndex = ref(0)
const totalPages = computed((): number => {
return Math.ceil(total.value / pageSize) || 1
})
onMounted(() => {
loadData()
})
async function loadData() {
isLoading.value = true
try {
const query: CouponQuery = {
name: filter.name || null,
type: typeOptions[typeIndex.value].value,
status: statusOptions[statusIndex.value].value,
page: page.value,
pageSize: pageSize
}
const res = await fetchAdminCoupons(query)
dataList.value = res.items
total.value = res.total
} catch (e) {
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
isLoading.value = false
}
}
function handleQuery() {
page.value = 1
loadData()
}
function handleAdd() {
uni.showToast({ title: '添加功能开发中', icon: 'none' })
}
async function toggleStatus(index: number) {
const item = dataList.value[index]
if (item.id == null) return
const currentStatus = item.status === 1
const success = await toggleCouponStatus(item.id!, !currentStatus)
if (success) {
uni.showToast({ title: '操作成功', icon: 'success' })
loadData()
}
}
async function handleDelete(id: string | undefined) {
if (id == null) return
uni.showModal({
title: '提示',
content: '确定删除该优惠券模板吗?',
success: async (res) => {
if (res.confirm) {
const success = await deleteCouponTemplate(id)
if (success) {
uni.showToast({ title: '删除成功', icon: 'success' })
loadData()
}
}
}
} as ShowModalOptions)
}
function onTypeChange(e: any) {
typeIndex.value = parseInt(String(e.detail.value))
handleQuery()
}
function onStatusFilterChange(e: any) {
statusIndex.value = parseInt(String(e.detail.value))
handleQuery()
}
function prevPage() {
if (page.value > 1) {
page.value--
loadData()
}
}
function nextPage() {
if (page.value < totalPages.value) {
page.value++
loadData()
}
}
function getTypeName(type: number): string {
const found = typeOptions.find(o => o.value === type)
return found ? found.label : '未知'
}
function getReceiveTypeName(receiveType: number): string {
return receiveType === 1 ? '用户领取' : '系统赠送'
}
function formatTime(iso: string | null): string {
if (!iso) return '-'
return iso.substring(0, 16).replace('T', ' ')
}
</script>