Files
medical-mall/pages/mall/admin/marketing/recharge/quota.uvue
2026-02-25 11:39:54 +08:00

384 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="marketing-recharge-quota">
<view class="content-layout">
<!-- 左侧预览 -->
<view class="preview-side">
<view class="phone-mock">
<view class="phone-header">
<text class="balance-label">我的余额</text>
<view class="balance-val">
<text class="symbol">¥</text>
<text class="num">0.00</text>
</view>
</view>
<view class="recharge-tabs">
<view class="tab active"><text class="tab-txt">账户充值</text></view>
<view class="tab"><text class="tab-txt">佣金导入</text></view>
</view>
<view class="quota-grid">
<view v-for="(item, index) in list" :key="index" class="quota-item" :class="{ active: index === 0 }">
<text class="price">{{ item.price }}元</text>
<text class="bonus">赠送{{ item.bonus }}元</text>
</view>
<view class="quota-item other">
<text class="other-txt">其他</text>
</view>
</view>
<view class="notice-section">
<text class="notice-title">注意事项:</text>
<text class="notice-content">充值后账户的金额不能提现可用于商城消费使用。佣金导入账户之后不能再次导出、不可提现。账户充值出现问题可联系商城客服也可拨打商城客服热线4008888888。</text>
</view>
<button class="recharge-btn">立即充值</button>
</view>
</view>
<!-- 右侧设置 -->
<view class="table-side border-shadow">
<view class="side-header">
<text class="side-title">充值金额设置</text>
</view>
<view class="action-row">
<button class="btn-primary" @click="showAddModal = true">添加数据</button>
</view>
<view class="table-container">
<view class="table-head">
<view class="th cell-id">编号</view>
<view class="th cell-price">售价</view>
<view class="th cell-bonus">赠送</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 list" :key="item.id" class="table-row">
<view class="td cell-id"><text class="td-txt">{{ item.id }}</text></view>
<view class="td cell-price"><text class="td-txt">{{ item.price }}</text></view>
<view class="td cell-bonus"><text class="td-txt">{{ item.bonus }}</text></view>
<view class="td cell-status">
<view class="switch-mock" :class="{ active: item.is_open }" @click="toggleStatus(item)">
<view class="switch-dot"></view>
</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>
<text class="op-link del ml-10" @click="handleDelete(item)">删除</text>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 添加数据弹窗 -->
<view v-if="showAddModal" class="modal-mask">
<view class="modal-content">
<view class="modal-header">
<text class="modal-title">添加数据</text>
<text class="modal-close" @click="showAddModal = false">×</text>
</view>
<view class="modal-body">
<view class="form-item">
<text class="form-label">售价:</text>
<input class="form-input" v-model="formData.price" type="number" placeholder="请输入售价" />
</view>
<view class="form-item">
<text class="form-label">赠送:</text>
<input class="form-input" v-model="formData.bonus" type="number" placeholder="请输入赠送" />
</view>
<view class="form-item">
<text class="form-label">排序:</text>
<input class="form-input" v-model="formData.sort" type="number" />
</view>
<view class="form-item">
<text class="form-label">状态:</text>
<view class="radio-group">
<view class="radio-item" @click="formData.is_open = true">
<view class="radio-circle" :class="{ checked: formData.is_open }"></view>
<text class="radio-txt">显示</text>
</view>
<view class="radio-item ml-20" @click="formData.is_open = false">
<view class="radio-circle" :class="{ checked: !formData.is_open }"></view>
<text class="radio-txt">隐藏</text>
</view>
</view>
</view>
</view>
<view class="modal-footer">
<button class="btn-cancel" @click="showAddModal = false">取消</button>
<button class="btn-submit" @click="handleSubmit">确定</button>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, reactive } from 'vue'
const showAddModal = ref(false)
const formData = reactive({
price: '',
bonus: '',
sort: 1,
is_open: true
})
const list = ref([
{ id: 640, price: 10, bonus: 2, is_open: true, sort: 6 },
{ id: 641, price: 20, bonus: 8, is_open: true, sort: 5 },
{ id: 642, price: 50, bonus: 20, is_open: true, sort: 4 },
{ id: 643, price: 100, bonus: 50, is_open: true, sort: 3 },
{ id: 644, price: 200, bonus: 110, is_open: true, sort: 2 },
{ id: 645, price: 300, bonus: 200, is_open: true, sort: 1 }
])
const toggleStatus = (item: any) => {
item.is_open = !item.is_open
uni.showToast({ title: '操作成功', icon: 'success' })
}
const handleEdit = (item: any) => {
uni.showToast({ title: '编辑功能', icon: 'none' })
}
const handleDelete = (item: any) => {
uni.showModal({
title: '提示',
content: '确认删除该项吗?',
success: (res) => {
if (res.confirm) {
const index = list.value.findIndex(i => i.id === item.id)
if (index > -1) {
list.value.splice(index, 1)
uni.showToast({ title: '已删除', icon: 'success' })
}
}
}
})
}
const handleSubmit = () => {
if (!formData.price) {
uni.showToast({ title: '请输入售价', icon: 'none' })
return
}
const newItem = {
id: Math.floor(Math.random() * 1000) + 700,
price: parseFloat(formData.price),
bonus: parseFloat(formData.bonus || '0'),
sort: parseInt(formData.sort.toString()),
is_open: formData.is_open
}
list.value.push(newItem)
// 重置表单
formData.price = ''
formData.bonus = ''
formData.sort = 1
formData.is_open = true
showAddModal.value = false
uni.showToast({ title: '添加成功', icon: 'success' })
}
</script>
<style scoped lang="scss">
.marketing-recharge-quota {
padding: 0;
background: transparent;
min-height: auto;
}
.content-layout {
display: flex;
flex-direction: row;
}
/* 左侧预览 */
.preview-side {
width: 320px;
margin-right: 24px;
}
.phone-mock {
background: #fff;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 16px rgba(0,0,0,0.1);
padding-bottom: 24px;
}
.phone-header {
height: 120px;
background: #e74c3c;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #fff;
}
.balance-label { font-size: 13px; opacity: 0.9; margin-bottom: 8px; }
.balance-val { display: flex; flex-direction: row; align-items: baseline; }
.symbol { font-size: 18px; margin-right: 4px; }
.num { font-size: 32px; font-weight: bold; }
.recharge-tabs {
display: flex;
flex-direction: row;
height: 44px;
border-bottom: 1px solid #f5f5f5;
}
.tab { flex: 1; display: flex; align-items: center; justify-content: center; position: relative; }
.tab.active::after { content: ''; position: absolute; bottom: 0; width: 40px; height: 2px; background: #e74c3c; }
.tab-txt { font-size: 14px; color: #666; font-weight: bold; }
.tab.active .tab-txt { color: #333; }
.quota-grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 16px;
justify-content: space-between;
}
.quota-item {
width: 90px;
height: 60px;
border: 1px solid #f0f0f0;
border-radius: 4px;
margin-bottom: 12px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #f8f8f8;
}
.quota-item.active {
border-color: #e74c3c;
background: #fff;
position: relative;
}
.quota-item.active::after {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
border: 1px solid #e74c3c;
border-radius: 4px;
}
.price { font-size: 14px; color: #333; font-weight: bold; margin-bottom: 4px; }
.bonus { font-size: 11px; color: #999; }
.quota-item.active .price { color: #e74c3c; }
.quota-item.active .bonus { color: #e74c3c; opacity: 0.8; }
.other { background: #f0f0f0; border: none; }
.other-txt { font-size: 14px; color: #666; }
.notice-section {
padding: 0 16px;
margin-top: 10px;
}
.notice-title { font-size: 13px; color: #333; font-weight: bold; margin-bottom: 8px; display: block; }
.notice-content { font-size: 12px; color: #999; line-height: 1.6; }
.recharge-btn {
margin: 24px 16px 0;
height: 40px;
line-height: 40px;
background: #e74c3c;
color: #fff;
border-radius: 20px;
font-size: 15px;
border: none;
}
/* 右侧设置 */
.table-side {
flex: 1;
background: #fff;
padding: 24px;
}
.border-shadow { border-radius: 4px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); }
.side-header { border-left: 4px solid #1890ff; padding-left: 12px; margin-bottom: 24px; }
.side-title { font-size: 16px; font-weight: bold; color: #333; }
.action-row { margin-bottom: 16px; }
.btn-primary {
background: #1890ff; color: #fff; border: none;
height: 32px; line-height: 32px; padding: 0 16px; font-size: 14px; border-radius: 4px; cursor: pointer;
}
.table-head { display: flex; flex-direction: row; background: #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-price { width: 120px; }
.cell-bonus { width: 120px; }
.cell-status { width: 100px; text-align: center; }
.cell-sort { width: 100px; text-align: center; }
.cell-op { flex: 1; text-align: right; }
.op-link { color: #1890ff; font-size: 13px; cursor: pointer; }
.op-link.del { color: #ff4d4f; }
.ml-10 { margin-left: 10px; }
.switch-mock {
width: 44px; height: 22px; background-color: #bfbfbf; border-radius: 11px;
display: flex; 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; }
/* Modal */
.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; }
.modal-header { padding: 16px 24px; border-bottom: 1px solid #e8eaec; display: flex; justify-content: space-between; align-items: center; }
.modal-title { font-size: 16px; font-weight: bold; }
.modal-close { font-size: 24px; color: #999; cursor: pointer; }
.modal-body { padding: 24px; }
.modal-footer { padding: 12px 24px; border-top: 1px solid #e8eaec; display: flex; justify-content: flex-end; }
.form-item { display: flex; flex-direction: row; margin-bottom: 20px; align-items: center; }
.form-label { width: 80px; font-size: 14px; color: #606266; }
.form-input { flex: 1; height: 32px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 0 12px; }
.radio-group { display: flex; flex-direction: row; flex: 1; }
.radio-item { display: flex; flex-direction: row; align-items: center; cursor: pointer; }
.radio-circle { width: 14px; height: 14px; border: 1px solid #dcdfe6; border-radius: 50%; margin-right: 6px; position: relative; }
.radio-circle.checked { border-color: #1890ff; }
.radio-circle.checked::after { content: ''; position: absolute; width: 8px; height: 8px; background: #1890ff; border-radius: 50%; top: 2px; left: 2px; }
.radio-txt { font-size: 14px; color: #606266; }
.ml-20 { margin-left: 20px; }
.btn-cancel { margin-right: 8px; height: 32px; line-height: 32px; padding: 0 16px; font-size: 14px; border-radius: 4px; border: 1px solid #dcdfe6; background: #fff; }
.btn-submit { height: 32px; line-height: 32px; padding: 0 16px; font-size: 14px; border-radius: 4px; background: #1890ff; color: #fff; border: none; }
</style>