大致完成页面

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>

View File

@@ -1,27 +1,225 @@
<template>
<AdminLayout :currentPage="currentPage">
<view class="page">
<view class="header">
<text class="title">{{ title }}</text>
<text class="sub-title">页面占位 (自动生成)</text>
<view class="marketing-member-config">
<view class="config-card border-shadow">
<view class="config-header">
<text class="config-title">会员基础配置</text>
</view>
<view class="config-body">
<view class="config-item">
<view class="item-label">
<text class="label-txt">是否开启付费会员:</text>
<text class="label-desc">关闭之后,商城将不再展示付费会员相关功能</text>
</view>
<view class="item-content">
<view class="switch-mock" :class="{ active: config.is_open }" @click="config.is_open = !config.is_open">
<view class="switch-dot"></view>
<text class="switch-txt">{{ config.is_open ? '开启' : '关闭' }}</text>
</view>
</view>
</view>
<view class="config-item">
<view class="item-label">
<text class="label-txt">会员期内背景图:</text>
<text class="label-desc">建议尺寸: 700*320px</text>
</view>
<view class="item-content">
<view class="upload-box" @click="handleUpload('bg')">
<image v-if="config.bg_img" :src="config.bg_img" class="preview-img"></image>
<view v-else class="upload-placeholder">
<text class="plus">+</text>
<text class="upload-txt">选择图片</text>
</view>
</view>
</view>
</view>
<view class="config-item">
<view class="item-label">
<text class="label-txt">会员到期背景图:</text>
<text class="label-desc">建议尺寸: 700*320px</text>
</view>
<view class="item-content">
<view class="upload-box" @click="handleUpload('expire_bg')">
<image v-if="config.expire_bg_img" :src="config.expire_bg_img" class="preview-img"></image>
<view v-else class="upload-placeholder">
<text class="plus">+</text>
<text class="upload-txt">选择图片</text>
</view>
</view>
</view>
</view>
<view class="config-item">
<view class="item-label">
<text class="label-txt">会员规则说明:</text>
<text class="label-desc">在会员中心页面展示的规则说明</text>
</view>
<view class="item-content flex-1">
<textarea class="config-textarea" v-model="config.rules" placeholder="请输入会员规则说明"></textarea>
</view>
</view>
<view class="config-footer">
<button class="btn btn-primary" @click="handleSave">保存配置</button>
</view>
</view>
</view>
</AdminLayout>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
import AdminLayout from '@/layouts/admin/AdminLayout.uvue'
const currentPage = ref<string>('member-config')
const title = ref<string>('config')
import { ref, reactive } from 'vue'
const config = reactive({
is_open: true,
bg_img: 'https://demo26.crmeb.net/uploads/attach/2021/11/20211115/a6f3b06e9d6d5a1b3c9d6d5a1b3c9d6d.png',
expire_bg_img: '',
rules: '1. 会员有效期自购买之日起计算\n2. 会员权益仅限本人使用\n3. 会员卡一经售出,概不退换'
})
const handleUpload = (type: string) => {
uni.showToast({ title: '文件管理器暂未开启', icon: 'none' })
}
const handleSave = () => {
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-config {
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);
}
.config-card {
padding: 24px;
}
.config-header {
border-bottom: 1px solid #e8eaec;
padding-bottom: 16px;
margin-bottom: 24px;
}
.config-title {
font-size: 16px;
font-weight: bold;
color: #17233d;
}
.config-item {
display: flex;
flex-direction: row;
margin-bottom: 30px;
align-items: flex-start;
}
.item-label {
width: 200px;
display: flex;
flex-direction: column;
}
.label-txt {
font-size: 14px;
color: #333;
margin-bottom: 4px;
}
.label-desc {
font-size: 12px;
color: #999;
}
.item-content {
flex: 1;
}
.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; }
.upload-box {
width: 120px;
height: 80px;
border: 1px dashed #dcdfe6;
border-radius: 4px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
}
.plus { font-size: 24px; color: #999; }
.upload-txt { font-size: 12px; color: #999; }
.preview-img { width: 100%; height: 100%; object-fit: cover; }
.config-textarea {
width: 100%;
max-width: 600px;
height: 120px;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 12px;
font-size: 14px;
}
.config-footer {
margin-top: 40px;
padding-left: 200px;
}
.btn-primary {
width: 120px;
height: 36px;
line-height: 36px;
background: #1890ff;
color: #fff;
border: none;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
}
.flex-1 { flex: 1; }
</style>

View File

@@ -1,27 +1,187 @@
<template>
<AdminLayout :currentPage="currentPage">
<view class="page">
<view class="header">
<text class="title">{{ title }}</text>
<text class="sub-title">页面占位 (自动生成)</text>
<view class="marketing-member-record">
<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>
</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-user">用户信息</view>
<view class="th cell-type">会员类型</view>
<view class="th cell-price">支付金额</view>
<view class="th cell-pay">支付方式</view>
<view class="th cell-time">购买时间</view>
<view class="th cell-expire">过期时间</view>
</view>
<view class="table-body">
<view v-for="item in records" :key="item.id" class="table-row">
<view class="td cell-id"><text class="td-txt">{{ item.id }}</text></view>
<view class="td cell-user">
<view class="user-box">
<image class="avatar" :src="item.avatar"></image>
<text class="nickname">{{ item.nickname }}</text>
</view>
</view>
<view class="td cell-type"><text class="td-txt">{{ item.member_type }}</text></view>
<view class="td cell-price"><text class="td-txt">¥{{ item.price.toFixed(2) }}</text></view>
<view class="td cell-pay"><text class="td-txt">{{ item.pay_type }}</text></view>
<view class="td cell-time"><text class="td-txt">{{ item.create_time }}</text></view>
<view class="td cell-expire"><text class="td-txt">{{ item.expire_time }}</text></view>
</view>
</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-record')
const title = ref<string>('record')
const records = ref([
{ id: 10, avatar: 'https://demo26.crmeb.net/uploads/attach/2021/11/20211115/a6f3b06e9d6d5a1b3c9d6d5a1b3c9d6d.png', nickname: '张三', member_type: '年卡会员', price: 99.00, pay_type: '微信支付', create_time: '2023-11-20 10:00:00', expire_time: '2024-11-20 10:00:00' },
{ id: 9, avatar: 'https://demo26.crmeb.net/uploads/attach/2021/11/20211115/a6f3b06e9d6d5a1b3c9d6d5a1b3c9d6d.png', nickname: '李四', member_type: '月卡会员', price: 9.90, pay_type: '余额支付', create_time: '2023-11-19 15:30:00', expire_time: '2023-12-19 15:30:00' },
{ id: 8, avatar: 'https://demo26.crmeb.net/uploads/attach/2021/11/20211115/a6f3b06e9d6d5a1b3c9d6d5a1b3c9d6d.png', nickname: '王五', member_type: '体验会员', price: 0.00, pay_type: '激活码', create_time: '2023-11-18 09:20:00', expire_time: '2023-11-25 09:20:00' }
])
</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-record {
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;
}
.filter-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 24px;
}
.label {
font-size: 14px;
color: #333;
width: 70px;
}
.input-mock {
width: 180px;
height: 32px;
border: 1px solid #dcdfe6;
border-radius: 4px;
padding: 0 12px;
font-size: 14px;
}
.select-mock {
width: 180px;
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;
}
.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-search { background: #1890ff; color: #fff; border: none; }
.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-user { flex: 1; }
.cell-type { width: 120px; }
.cell-price { width: 100px; }
.cell-pay { width: 100px; }
.cell-time { width: 160px; }
.cell-expire { width: 160px; }
.user-box {
display: flex;
flex-direction: row;
align-items: center;
}
.avatar {
width: 32px;
height: 32px;
border-radius: 16px;
margin-right: 8px;
}
.nickname { font-size: 13px; color: #515a6e; }
</style>

View File

@@ -0,0 +1,142 @@
<template>
<view class="marketing-member-right">
<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-icon">权益图标</view>
<view class="th cell-name">权益名称</view>
<view class="th cell-desc">权益简介</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-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>
</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-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-op">
<text class="op-link" @click="handleEdit(item)">编辑</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
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 toggleStatus = (item: any) => {
item.is_show = !item.is_show
uni.showToast({ title: '修改成功', icon: 'success' })
}
const handleEdit = (item: any) => {
uni.showToast({ title: '编辑功能开发中', icon: 'none' })
}
</script>
<style scoped lang="scss">
.marketing-member-right {
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);
}
.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: 80px; }
.cell-icon { width: 100px; text-align: center; }
.cell-name { width: 150px; }
.cell-desc { flex: 1; }
.cell-status { width: 120px; text-align: center; }
.cell-sort { width: 100px; text-align: center; }
.cell-op { width: 80px; text-align: right; }
.right-icon {
width: 40px;
height: 40px;
}
.switch-mock {
width: 50px;
height: 24px;
background-color: #bfbfbf;
border-radius: 12px;
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: 16px;
height: 16px;
background-color: #fff;
border-radius: 50%;
position: absolute;
left: 4px;
transition: left 0.3s;
}
.switch-mock.active .switch-dot { left: 30px; }
.switch-txt { font-size: 11px; color: #fff; margin-left: 20px; }
.switch-mock.active .switch-txt { margin-left: 4px; }
.op-link { color: #1890ff; font-size: 13px; cursor: pointer; }
</style>

View File

@@ -1,27 +0,0 @@
<template>
<AdminLayout :currentPage="currentPage">
<view class="page">
<view class="header">
<text class="title">{{ title }}</text>
<text class="sub-title">页面占位 (自动生成)</text>
</view>
</view>
</AdminLayout>
</template>
<script setup lang="uts">
import { ref } from 'vue'
import AdminLayout from '@/layouts/admin/AdminLayout.uvue'
const currentPage = ref<string>('member-rights')
const title = ref<string>('rights')
</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; }
</style>

View File

@@ -1,27 +1,147 @@
<template>
<AdminLayout :currentPage="currentPage">
<view class="page">
<view class="header">
<text class="title">{{ title }}</text>
<text class="sub-title">页面占位 (自动生成)</text>
<view class="marketing-member-type">
<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-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-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>
<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>
</view>
</view>
</view>
</view>
</AdminLayout>
</view>
</template>
<script setup lang="uts">
import { ref } from 'vue'
import AdminLayout from '@/layouts/admin/AdminLayout.uvue'
const currentPage = ref<string>('member-type')
const title = ref<string>('type')
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 toggleStatus = (item: any) => {
item.is_open = !item.is_open
uni.showToast({ title: '修改成功', icon: 'success' })
}
const handleEdit = (item: any) => {
uni.showToast({ title: '编辑功能开发中', icon: 'none' })
}
</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-type {
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);
}
.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: 80px; }
.cell-name { flex: 1; min-width: 150px; }
.cell-days { width: 120px; }
.cell-price { width: 120px; }
.cell-discount { width: 120px; }
.cell-status { width: 120px; text-align: center; }
.cell-sort { width: 100px; text-align: center; }
.cell-op { width: 80px; text-align: right; }
.switch-mock {
width: 50px;
height: 24px;
background-color: #bfbfbf;
border-radius: 12px;
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: 16px;
height: 16px;
background-color: #fff;
border-radius: 50%;
position: absolute;
left: 4px;
transition: left 0.3s;
}
.switch-mock.active .switch-dot { left: 30px; }
.switch-txt { font-size: 11px; color: #fff; margin-left: 20px; }
.switch-mock.active .switch-txt { margin-left: 4px; }
.op-link { color: #1890ff; font-size: 13px; cursor: pointer; }
</style>