大致完成页面

This commit is contained in:
2026-02-05 09:01:16 +08:00
parent c411c23b9c
commit d51e6a8f72
40 changed files with 11023 additions and 737 deletions

View File

@@ -1,27 +1,343 @@
<template>
<AdminLayout :currentPage="currentPage">
<view class="page">
<view class="header">
<text class="title">{{ title }}</text>
<text class="sub-title">页面占位 (自动生成)</text>
<view class="marketing-member-card">
<view class="filter-card border-shadow">
<view class="filter-row">
<view class="filter-item">
<text class="label">批次搜索:</text>
<input class="input-mock" placeholder="请输入批次名" />
</view>
<view class="filter-item">
<text class="label">是否开启:</text>
<view class="select-mock">
<text class="select-val">全部</text>
<text class="arrow">▼</text>
</view>
</view>
<view class="btn-group">
<button class="btn btn-search">查询</button>
<button class="btn btn-reset">重置</button>
</view>
</view>
<view class="action-row">
<button class="btn btn-primary" @click="showAddBatch = true">+ 添加批次</button>
</view>
</view>
</AdminLayout>
<view class="table-card border-shadow">
<view class="table-container">
<view class="table-head">
<view class="th cell-id">ID</view>
<view class="th cell-name">批次名称</view>
<view class="th cell-num">体验卡数量</view>
<view class="th cell-type">会员类型</view>
<view class="th cell-time">生效时间</view>
<view class="th cell-status">是否启用</view>
<view class="th cell-op">操作</view>
</view>
<view class="table-body">
<view v-for="item in cards" :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.title }}</text></view>
<view class="td cell-num"><text class="td-txt">{{ item.use_num }}/{{ item.total_num }}</text></view>
<view class="td cell-type"><text class="td-txt">{{ item.member_type }}</text></view>
<view class="td cell-time"><text class="td-txt">{{ item.create_time }}</text></view>
<view class="td cell-status">
<view class="switch-mock" :class="{ active: item.status }" @click="toggleStatus(item)">
<view class="switch-dot"></view>
<text class="switch-txt">{{ item.status ? '开启' : '关闭' }}</text>
</view>
</view>
<view class="td cell-op">
<text class="op-link" @click="showQrCode(item)">二维码</text>
<text class="op-link ml-10" @click="viewDetails(item)">详情</text>
</view>
</view>
</view>
</view>
</view>
<!-- 添加批次弹窗 -->
<view v-if="showAddBatch" class="modal-mask">
<view class="modal-content">
<view class="modal-header">
<text class="modal-title">添加批次</text>
<text class="modal-close" @click="showAddBatch = false">×</text>
</view>
<view class="modal-body">
<view class="form-item">
<text class="form-label">批次名称:</text>
<input class="form-input" placeholder="请输入批次名称" />
</view>
<view class="form-item">
<text class="form-label">导入数量:</text>
<input class="form-input" type="number" placeholder="请输入生成数量" />
</view>
<view class="form-item">
<text class="form-label">会员类型:</text>
<view class="form-select">
<text>请选择会员类型</text>
<text class="arrow">▼</text>
</view>
</view>
<view class="form-item">
<text class="form-label">备注:</text>
<textarea class="form-textarea" placeholder="请输入备注"></textarea>
</view>
</view>
<view class="modal-footer">
<button class="btn btn-cancel" @click="showAddBatch = false">取消</button>
<button class="btn btn-submit" @click="handleAddSubmit">提交</button>
</view>
</view>
</view>
<!-- 二维码弹窗 -->
<view v-if="showQrModal" class="modal-mask">
<view class="modal-content qr-modal">
<view class="modal-header">
<text class="modal-title">预览体验卡二维码</text>
<text class="modal-close" @click="showQrModal = false">×</text>
</view>
<view class="modal-body qr-body">
<image class="qr-img" src="https://demo26.crmeb.net/uploads/attach/2021/11/20211115/a6f3b06e9d6d5a1b3c9d6d5a1b3c9d6d.png" mode="aspectFit"></image>
<text class="qr-tips">请扫码体验会员卡</text>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
import AdminLayout from '@/layouts/admin/AdminLayout.uvue'
const currentPage = ref<string>('member-card')
const title = ref<string>('card')
const showAddBatch = ref(false)
const showQrModal = ref(false)
const cards = ref([
{ id: 4, title: '双11体验卡', use_num: 1, total_num: 100, member_type: '年卡会员', create_time: '2023-11-01 12:00:00', status: true },
{ id: 3, title: '新人体验卷', use_num: 50, total_num: 200, member_type: '月卡会员', create_time: '2023-10-25 09:30:00', status: true },
{ id: 2, title: '测试批次', use_num: 0, total_num: 10, member_type: '季卡会员', create_time: '2023-10-20 15:45:00', status: false }
])
const toggleStatus = (item: any) => {
item.status = !item.status
uni.showToast({ title: '操作成功', icon: 'success' })
}
const showQrCode = (item: any) => {
showQrModal.value = true
}
const viewDetails = (item: any) => {
uni.showToast({ title: '查看详情: ' + item.title, icon: 'none' })
}
const handleAddSubmit = () => {
showAddBatch.value = false
uni.showToast({ title: '添加成功', icon: 'success' })
}
</script>
<style scoped lang="scss">
@import '@/uni.scss';
.page { padding: $space-lg; }
.header { padding: $space-lg; border-radius: $radius; background: $background-primary; box-shadow: $shadow-xs; }
.title { font-size: $font-size-lg; font-weight: $font-weight-bold; color: $text-primary; }
.sub-title { margin-top: $space-xs; font-size: $font-size-md; color: $text-secondary; }
.marketing-member-card {
padding: 16px;
background: #f0f2f5;
min-height: 100vh;
}
.border-shadow {
background: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
.filter-card {
padding: 24px;
margin-bottom: 16px;
}
.filter-row {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: wrap;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 24px;
margin-bottom: 16px;
}
.label {
font-size: 14px;
color: #333;
width: 80px;
}
.input-mock {
width: 200px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 0 12px;
font-size: 14px;
}
.select-mock {
width: 200px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 0 12px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.select-val { font-size: 14px; color: #606266; }
.arrow { font-size: 10px; color: #c0c4cc; }
.btn-group {
display: flex;
flex-direction: row;
margin-bottom: 16px;
}
.btn {
height: 32px;
line-height: 32px;
padding: 0 20px;
font-size: 14px;
border-radius: 4px;
cursor: pointer;
margin-right: 8px;
background: #fff;
border: 1px solid #dcdfe6;
color: #606266;
}
.btn-primary { background: #1890ff; color: #fff; border: none; }
.btn-search { background: #1890ff; color: #fff; border: none; }
.btn-reset { margin-left: 8px; }
.action-row {
margin-top: 8px;
}
.table-card { padding: 24px; }
.table-head {
display: flex;
flex-direction: row;
background-color: #f8f8f9;
border-bottom: 1px solid #e8eaec;
}
.th { padding: 12px 8px; font-size: 13px; color: #515a6e; font-weight: bold; }
.table-row {
display: flex;
flex-direction: row;
border-bottom: 1px solid #e8eaec;
align-items: center;
}
.td { padding: 16px 8px; }
.td-txt { font-size: 13px; color: #515a6e; }
.cell-id { width: 60px; }
.cell-name { flex: 1; }
.cell-num { width: 120px; }
.cell-type { width: 120px; }
.cell-time { width: 160px; }
.cell-status { width: 100px; }
.cell-op { width: 120px; text-align: right; }
.op-link { color: #1890ff; font-size: 13px; cursor: pointer; }
.ml-10 { margin-left: 10px; }
.switch-mock {
width: 44px;
height: 22px;
background-color: #bfbfbf;
border-radius: 11px;
display: flex;
flex-direction: row;
align-items: center;
padding: 0 4px;
position: relative;
transition: background-color 0.3s;
cursor: pointer;
}
.switch-mock.active { background-color: #1890ff; }
.switch-dot {
width: 14px;
height: 14px;
background-color: #fff;
border-radius: 50%;
position: absolute;
left: 4px;
transition: left 0.3s;
}
.switch-mock.active .switch-dot { left: 26px; }
.switch-txt { font-size: 10px; color: #fff; margin-left: 18px; }
.switch-mock.active .switch-txt { margin-left: 4px; }
/* Modal Styles */
.modal-mask {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
width: 500px;
background: #fff;
border-radius: 4px;
overflow: hidden;
}
.modal-header {
padding: 16px 24px;
border-bottom: 1px solid #e8eaec;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.modal-title { font-size: 16px; font-weight: bold; color: #17233d; }
.modal-close { font-size: 24px; color: #909399; cursor: pointer; }
.modal-body { padding: 24px; }
.modal-footer {
padding: 12px 24px;
border-top: 1px solid #e8eaec;
display: flex;
flex-direction: row;
justify-content: flex-end;
}
.form-item {
display: flex;
flex-direction: row;
margin-bottom: 20px;
align-items: flex-start;
}
.form-label { width: 100px; font-size: 14px; color: #606266; padding-top: 6px; }
.form-input { flex: 1; height: 32px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 0 12px; }
.form-select { flex: 1; height: 32px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 0 12px; display: flex; flex-direction: row; align-items: center; justify-content: space-between; color: #c0c4cc; font-size: 14px; }
.form-textarea { flex: 1; height: 80px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 8px 12px; }
.btn-cancel { margin-right: 8px; }
.btn-submit { background: #1890ff; color: #fff; border: none; }
.qr-modal { width: 300px; }
.qr-body { display: flex; flex-direction: column; align-items: center; }
.qr-img { width: 200px; height: 200px; margin-bottom: 16px; }
.qr-tips { font-size: 14px; color: #666; }
</style>