|
|
<script setup> import { onMounted, reactive, ref, watch } from "vue"; import { ElIcon, ElMessage, ElMessageBox } from "element-plus"; import moment from "moment"; import request from "@/util/http.js" import Cookies from 'js-cookie'; import { useAdminStore } from "@/store/index.js"; import { storeToRefs } from "pinia"; import { WarnTriangleFilled } from "@element-plus/icons-vue"; import dayjs from "dayjs";
const adminStore = useAdminStore(); const { adminData, menuTree } = storeToRefs(adminStore); // 精网号去空格
const trimJwCode = () => { if (addConsume.value.jwcode) { // 去除所有空格,并尝试转换为整数
const trimmed = addConsume.value.jwcode.toString().replace(/\s/g, '') const numeric = Number(trimmed)
// 如果转换为数字成功,保存为数字,否则提示错误
if (!isNaN(numeric)) { addConsume.value.jwcode = numeric } else { ElMessage.error("精网号格式不正确,请输入数字") } } } //提交禁止重复点击
const addDisabled = ref(false) // 通过精网号查询用户(客户)信息 表单
const user = ref({ jwcode: null, name: "", market: "", historySumGold: null, historyPermanentGold: null, historyFreeGold: null, historyTaskGold: null, rechargeNum: null, consumeNum: null, firstRecharge: "", nowPermanentGold: null, nowFreeJune: null, nowTaskGold: null, nowFreeDecember: null, nowFreeGold: null, nowSumGold: null })
// 这是添加消费信息的表单(金币)
const addConsume = ref({ // jwcode 是数字
jwcode: null, //精网号
goodsName: "",// 商品名称
sumGold: null, // 消费金币总数
freeGold: null, // 免费金币
permanentGold: null, // 永久金币
taskGold: null, // 任务金币
remark: "",//备注
adminId: null,// 当前管理员id
adminName: adminData.value.adminName }) const Ref = ref(null) const rules = reactive({ jwcode: [ { required: true, message: "请输入精网号", trigger: "blur" }, ], goodsName: [{ required: true, message: "请选择商品", trigger: "change" }], sumGold: [ { required: true, message: "消耗金币总数不能为空", trigger: "blur" }, { validator: (rule, value, callback) => { // 允许0开头的小数(如0.1)但不允许单独的0
const isValid = /^(0\.\d{1,2})|([1-9]\d*(\.\d{1,2})?)$/.test(value);
if (!isValid) { callback(new Error("请输入大于0的正数(可包含最多两位小数)")); } else { callback(); } }, trigger: "blur" } ] }); // 查询商品的表单
const goods = ref([])
// 输入验证函数
function validateInput() { const sumGold = parseFloat(addConsume.value.sumGold); trimJwCode();
if (user.value.jwcode == null) { ElMessage.warning("请先查询用户信息"); addConsume.value.sumGold = null; user.value = {}; return false; }
/* 这块逻辑加到规则里面 // 验证金币数值
if (user.value.jwcode && (isNaN(sumGold) || sumGold <= 0)) { ElMessage.warning("消费金币总数必须是大于0的数字"); // 将sumGold设置为null
addConsume.value.sumGold = null; return false; } */ // sumGold 补充0(比如.1 为0.1)
if (addConsume.value.sumGold && addConsume.value.sumGold.toString().startsWith('.')) { addConsume.value.sumGold = '0' + addConsume.value.sumGold; // ElMessage.info('已自动补充前导0');
} // 验证金币不能为负数
if (sumGold < 0) { ElMessage.warning("消耗金币总数不能为负数"); addConsume.value.sumGold = null; return false; }
// 小数位数限制 2位,整数位数限制 6位
if (addConsume.value.sumGold) { const sumGoldStr = addConsume.value.sumGold.toString();
// 检查整数部分长度
if (sumGoldStr.includes('.')) { const integerPart = sumGoldStr.split('.')[0]; if (integerPart.length > 6) { // 截断整数部分到6位并提示
const truncatedInteger = integerPart.slice(0, 6); addConsume.value.sumGold = parseFloat(truncatedInteger); ElMessage.info('整数部分最多允许6位'); return; // 直接返回,不再处理小数部分
} } else { // 纯整数情况
if (sumGoldStr.length > 6) { addConsume.value.sumGold = parseFloat(sumGoldStr.slice(0, 6)); ElMessage.info('整数部分最多允许6位'); return; } }
// 处理小数部分
if (sumGoldStr.includes('.')) { const decimalPart = sumGoldStr.split('.')[1]; if (decimalPart.length > 2) { // 截断到两位小数并提示
const truncatedValue = parseFloat(sumGoldStr.slice(0, sumGoldStr.indexOf('.') + 3)); addConsume.value.sumGold = truncatedValue; ElMessage.info('最多允许输入两位小数'); } } }
// 验证金币总和
const totalAvailableGold = (user.value.nowSumGold) if (user.value.jwcode && sumGold > totalAvailableGold) { ElMessage.error("消耗金币总数超过可用金币总和"); // 将sumGold设置为null
addConsume.value.sumGold = null; return false; }
return true; }
// 消耗金币计算函数
function calculateCoins(sumGold) { console.log("消耗金币计算函数:计算金币", sumGold); const parsedSumGold = parseFloat(sumGold); if (isNaN(parsedSumGold) || parsedSumGold <= 0 || !user.value.jwcode) { return { free: 0, permanent: 0, task: 0 }; }
const { nowFreeGold, nowPermanentGold, nowTaskGold } = user.value; let remaining = parsedSumGold; let freeUsed = 0, permanentUsed = 0, taskUsed = 0;
// 优先消耗免费金币
if (nowFreeGold > 0) { freeUsed = Math.min(parseFloat(nowFreeGold.toFixed(4)), remaining); remaining = parseFloat((remaining - freeUsed).toFixed(4)); }
// 其次消耗永久金币
if (remaining > 0 && nowPermanentGold > 0) { permanentUsed = Math.min(parseFloat(nowPermanentGold.toFixed(4)), remaining); remaining = parseFloat((remaining - permanentUsed).toFixed(4)); }
// 最后消耗任务金币
if (remaining > 0 && nowTaskGold > 0) { taskUsed = parseFloat(remaining.toFixed(4)); }
// 更新金币值
addConsume.value.freeGold = freeUsed; addConsume.value.permanentGold = permanentUsed; addConsume.value.taskGold = taskUsed;
return { free: freeUsed, permanent: permanentUsed, task: taskUsed }; }
// 用来写的 cookie 的 key
const WriteCookies = ref(null) // 用来写的 cookie 的 value
const WriteCookiesTime = ref(null) // 用来读的 cookie 的 key
const ReadCookies = ref(null) // 用来读的 cookie 的 value
const ReadCookiesTime = ref(null) // 这是添加消费信息的接口
const add = async function () { try { // 验证输入数据 再验证一次
if (!validateInput()) { return; } // 计算金币使用情况
calculateCoins(addConsume.value.sumGold);
console.log("addConsume.value", addConsume.value)
//存一下 用户的jwcode
// 拼接 jwcode:permanentGold:freeGold
WriteCookies.value = `coinConsume:${addConsume.value.jwcode}:${addConsume.value.goodsName.value}` //value 为当前消耗时间
WriteCookiesTime.value = dayjs().format("YYYY-MM-DD HH:mm:ss"); // 设置cookies,用户jwcode为key,value也是jwcode,过期时间为1天
Cookies.set(WriteCookies.value, WriteCookiesTime.value, { expires: 1, path: '/' });
addDisabled.value = true // 发送POST请求
const result = await request({ url: "/consume/add", data: { jwcode: addConsume.value.jwcode, adminId: adminData.value.id, sumGold: addConsume.value.sumGold * 100, freeGold: addConsume.value.freeGold * 100, taskGold: addConsume.value.taskGold * 100, permanentGold: addConsume.value.permanentGold * 100, goodsName: addConsume.value.goodsName.value, remark: addConsume.value.remark, adminName: adminData.value.adminName } }) addDisabled.value = false console.log("add请求", result); // 处理响应
handleResponse(result); // 重置表单
resetForm();
} catch (error) { console.error("请求失败", error); ElMessage.error("添加失败,请检查网络连接或联系管理员"); } };
// 响应处理函数
function handleResponse(result) { console.log("响应结果", result) if (result.code === 200) { ElMessage.success("添加成功"); console.log("请求成功", result); } else { ElMessage.error(result.msg || "添加失败,未知错误"); } }
// 重置表单函数
function resetForm() { // 清空表单数据
Ref.value.resetFields();
addConsume.value = { jwcode: null, goodsName: "", sumGold: null, freeGold: null, permanentGold: null, taskGold: null, remark: "", adminId: adminData.value.id, adminName: adminData.value.adminName, }
console.log("重置表单")
user.value = { jwcode: null, name: "", market: "", historySumGold: null, historyPermanentGold: null, historyFreeGold: null, historyTaskGold: null, rechargeNum: null, consumeNum: null, firstRecharge: "", nowPermanentGold: null, nowFreeJune: null, nowTaskGold: null, nowFreeDecember: null, nowFreeGold: null, nowSumGold: null } }
// 充值对话框显示状态
const ConsumeDialogVisible = ref(false);
// 关闭对话框
const ConsumeDialogVisiblehandleClose = () => { ConsumeDialogVisible.value = false; // 重置表单数据
resetForm() user.value = {} }; `` // 确认使用cookie继续充值
const ConsumeDialogVisibleContinue = () => { ConsumeDialogVisible.value = false; add(); };
const ConsumeDialogVisibleCancel = () => { ConsumeDialogVisible.value = false resetForm() user.value = {} };
// 第一次弹窗
// 充值对话框显示状态
const FirstConsumeDialogVisible = ref(false);
// 关闭对话框
const FirstConsumeDialogVisiblehandleClose = () => { FirstConsumeDialogVisible.value = false; // 重置表单数据
resetForm() user.value = {} };
// 第一次消耗
const FirstConsumeDialogVisibleContinue = () => { FirstConsumeDialogVisible.value = false; add(); };
const FirstConsumeDialogVisibleCancel = () => { FirstConsumeDialogVisible.value = false resetForm() user.value = {} };
// 实际执行充值操作
// const proceedWithConsume = () => {
// ElMessageBox.confirm('确认购买?')
// .then(() => {
// add();
// console.log('添加成功');
// })
// .catch(() => {
// console.log('取消添加');
// });
// };
// 添加前验证
const addBefore = () => { Ref.value.validate(async (valid) => { // 验证cookie
if (!valid) { ElMessage({ type: 'error', message: '请检查输入内容' }); return; } ReadCookies.value = `coinConsume:${addConsume.value.jwcode}:${addConsume.value.goodsName.value}` // 获取cookie
const cookie = Cookies.get(ReadCookies.value) console.log("time", WriteCookiesTime.value) // 格式化时间
ReadCookiesTime.value = moment(cookie).format('YYYY-MM-DD HH:mm:ss') console.log("cookie========", cookie) if (cookie) { ConsumeDialogVisible.value = true; } else { FirstConsumeDialogVisible.value = true; } }); };
// 查询客户信息(通过精网号)
const getUser = async function (jwcode) { try { // 验证精网号
if (!jwcode) { ElMessage.warning('精网号不能为空'); return; }
// 验证精网号是否为数字
if (!/^\d{1,9}$/.test(jwcode)) { ElMessage.warning('精网号必须为数字且不超过九位'); resetForm() return; }
// 发送POST请求
const result = await request({ url: "/user/selectUser", data: { jwcode } });
console.log("请求成功", result);
if (result.code === 200 && result.data) { // 处理用户数据
user.value = { ...result.data, // 统一处理所有黄金数值,除以100
nowPermanentGold: result.data.nowPermanentGold, nowFreeGold: result.data.nowFreeGold, nowSumGold: result.data.nowSumGold, nowTaskGold: result.data.nowTaskGold, nowFreeJune: result.data.nowFreeJune, nowFreeDecember: result.data.nowFreeDecember, historySumGold: result.data.historySumGold, historyPermanentGold: result.data.historyPermanentGold, historyFreeGold: result.data.historyFreeGold, historyTaskGold: result.data.historyTaskGold };
ElMessage.success("查询成功"); // 检查sumGold是否有值,如果有则重新计算金币分配
if (addConsume.value.sumGold) { const parsedSumGold = parseFloat(addConsume.value.sumGold); if (!isNaN(parsedSumGold) && parsedSumGold > 0) { const { free, permanent, task } = calculateCoins(parsedSumGold); addConsume.value.freeGold = free; addConsume.value.permanentGold = permanent; addConsume.value.taskGold = task; } } // 验证输入
validateInput()
} else if (!result.data) { ElMessage.warning("用户不存在"); user.value.jwcode = null addConsume.value.jwcode = null // resetForm(); // 重置表单
} else { ElMessage.warning(result.msg || "请检查查询参数"); } } catch (error) { console.error("请求失败", error); ElMessage.error("查询失败,请检查网络连接或精网号是否正确"); resetForm(); // 重置表单
} }; // 获取商品信息(三楼接口)
const getGoods = async function () { try { // 发送POST请求
const result = await request({ // url: "/product", //
// url: "http://39.101.133.168:8828/live_mall/api/product/all",
url: "https://api.homilychart.com/live_mall/api/product/all", }); // 将响应结果存储到响应式数据中
console.log("请求成功", result); goods.value = result.data.map(item => ({ id: item.id, label: item.name, value: item.name })); } catch (error) { console.log("请求失败", error); // 在这里可以处理错误逻辑,比如显示错误提示等
} };
/* ====================监听================================= */
// 监听消费总金额变化,自动计算三类金币
watch( () => addConsume.value.sumGold, (newValue) => { const parsedNewValue = parseFloat(newValue); if (!isNaN(parsedNewValue) && parsedNewValue > 0) { const { free, permanent, task } = calculateCoins(parsedNewValue); addConsume.value.freeGold = free; addConsume.value.permanentGold = permanent; addConsume.value.taskGold = task; } else { addConsume.value.freeGold = null; addConsume.value.permanentGold = null; addConsume.value.taskGold = null; } } );
/* ====================挂载================================= */ // 挂载
onMounted(async function () { await getGoods() console.log('adminData', adminData.value) })
</script>
<template> <div class="father1"> <div class="left"> <el-form :model="addConsume" ref="Ref" :rules="rules" style="min-width: 420px;" class="add-form" label-width="auto" label-position="right"> <el-form-item prop="jwcode" label="精网号" style="margin-top: 50px"> <el-input v-model="addConsume.jwcode" style="width: 200px;" /> <el-button type="primary" @click="getUser(addConsume.jwcode)" style="margin-left: 20px">查询 </el-button> </el-form-item>
<el-form-item prop="goodsName" label="商品名称"> <el-select v-model="addConsume.goodsName" placeholder="请选择商品" style="width: 200px" clearable filterable> <el-option v-for="(item, index) in goods" :key="index" :label="item.label" :value="item" />
</el-select> </el-form-item>
<el-form-item prop="sumGold" label="消耗金币总数"> <el-input v-model="addConsume.sumGold" style="width: 120px" @input="validateInput()" @change="calculateCoins(addConsume.sumGold)" /> </el-form-item>
<!-- 三类金币自动计算(禁用状态,不可编辑) -->
<el-form-item prop="permanentGold" label="永久金币"> <el-input v-model="addConsume.permanentGold" disabled style="width: 120px"> <template #default="scope">{{ scope.row.permanentGold }}</template> </el-input> <p style="margin-right: 0px"> 个</p> </el-form-item>
<el-form-item prop="freeCoin" label="免费金币"> <el-input disabled v-model="addConsume.freeGold" style="width: 120px" /> <p style="margin-right: 0px"> 个</p> </el-form-item>
<el-form-item prop="taskGold" label="任务金币"> <el-input disabled v-model="addConsume.taskGold" style="width: 120px" /> <p style="margin-right: 20px"> 个</p> </el-form-item>
<el-form-item prop="remark" label="备注"> <el-input v-model="addConsume.remark" style="width: 250px" :rows="4" maxlength="100" show-word-limit type="textarea" /> </el-form-item>
<el-button type="success" @click="resetForm()" style="margin-left: 200px;margin-top:10px">重置</el-button> <el-button type="primary" :disabled="addDisabled" @click="addBefore" style="margin-top:10px"> 提交</el-button> </el-form> </div>
<div class="right"> <!-- 客户信息栏 --> <el-card v-if="user.jwcode" style="width: 800px; float: right" class="customer-info"> <el-form :model="user" label-width="auto" style="max-width: 1000px" label-position="left"> <el-text size="large" style="margin-left: 20px">客户信息</el-text>
<!-- 第一行:姓名 + 历史金币 --> <el-row style="margin-top: 20px"> <el-col :span="9"> <el-form-item label="姓名"> <p>{{ user.name }}</p> </el-form-item> </el-col> <el-col :span="14"> <el-form-item label="当前金币总数" style="width: 500px"> <span style="color: #2fa1ff; margin-right: 5px" v-if="user.nowSumGold !== undefined">{{ user.nowSumGold }}</span> </el-form-item> <!-- 金币详情独立显示 --> <el-form-item style="margin-top: -23px"> <!-- 负边距减少间距 --> <span style="color: #b1b1b1; margin-left: 0px" v-if="user.nowPermanentGold !== undefined">(永久金币:{{ user.nowPermanentGold }}; 免费金币:{{ user.nowFreeGold }}; 任务金币:{{ user.nowTaskGold }})</span> </el-form-item> </el-col> </el-row>
<!-- 第二行:精网号 + 当前金币(独立行) --> <el-row> <el-col :span="9"> <el-form-item label="精网号"> <p>{{ user.jwcode }}</p> </el-form-item> </el-col> <el-col :span="14"> <el-form-item label="消费次数"> <p style="color: #2fa1ff">{{ user.consumeNum }} </p> </el-form-item> <el-form-item style="margin-top: -23px"> <!-- 负边距减少间距 --> <p style="font-size: small; color: #b1b1b1">(仅统计2025-01-01后的数据)</p> </el-form-item> </el-col> </el-row>
<!-- 第三行:首次充值日期 + 充值次数 --> <!-- <el-row > <el-col :span="9"> <el-form-item label="首次充值日期"> <p v-if="user.firstRecharge"> {{ moment(user.firstRecharge).format('YYYY-MM-DD HH:mm:ss') }} </p> </el-form-item> </el-col> </el-row> -->
<!-- 第四行:消费次数 + 所属门店 --> <el-row> <el-col :span="9"> <el-form-item label="所属门店"> <p>{{ user.market }}</p> </el-form-item> </el-col> </el-row> </el-form> </el-card>
<el-dialog v-model="FirstConsumeDialogVisible" title="操作确认" :before-close="FirstConsumeDialogVisiblehandleClose" :close-on-click-modal="false" width="480px"> <!-- 内容整体居中且收窄 --> <div class="confirm-body"> <!-- 用户信息 --> <div> <div class="field-label">用户信息</div> <el-input :model-value="user.jwcode + (user.name ? '【' + user.name + '】' : '')" disabled /> </div> <!-- 活动名称 --> <div class="field"> <div class="field-label">商品名称</div> <el-input v-model="addConsume.goodsName.value" disabled /> </div> <!--金币总数 --> <div class="field"> <div class="field-label">金币总数</div> <el-input v-model="addConsume.sumGold" disabled /> </div> <!-- 金币详细信息(同一行左右排列) --> <el-row :gutter="20" class="coins-row"> <el-col :span="8"> <div class="field"> <div class="field-label">永久金币</div> <el-input v-model="addConsume.permanentGold" disabled /> </div> </el-col> <el-col :span="8"> <div class="field"> <div class="field-label">免费金币</div> <el-input v-model="addConsume.freeGold" disabled /> </div> </el-col> <el-col :span="8"> <div class="field"> <div class="field-label">任务金币</div> <el-input v-model="addConsume.taskGold" disabled /> </div> </el-col>
</el-row>
<div class="field"> <div class="field-label">备注</div> <el-input v-model="addConsume.remark" disabled /> </div> </div>
<!-- 底部按钮(居中) --> <template #footer> <div class="dialog-footer-center"> <el-button @click="FirstConsumeDialogVisibleCancel">取 消</el-button> <el-button type="primary" @click="FirstConsumeDialogVisibleContinue">确认购买</el-button> </div> </template> </el-dialog>
<el-dialog v-model="ConsumeDialogVisible" title="第二次操作确认" :before-close="ConsumeDialogVisiblehandleClose" :close-on-click-modal="false" width="480px"> <!-- 内容整体居中且收窄 --> <div class="confirm-body"> <!-- 用户信息 --> <div> <div class="field-label">用户信息</div> <el-input :model-value="user.jwcode + (user.name ? '【' + user.name + '】' : '')" disabled /> </div> <!-- 活动名称 --> <div class="field"> <div class="field-label">商品名称</div> <el-input v-model="addConsume.goodsName.value" disabled /> </div> <!--金币总数 --> <div class="field"> <div class="field-label">金币总数</div> <el-input v-model="addConsume.sumGold" disabled /> </div> <!-- 金币详细信息(同一行左右排列) --> <el-row :gutter="20" class="coins-row"> <el-col :span="8"> <div class="field"> <div class="field-label">永久金币</div> <el-input v-model="addConsume.permanentGold" disabled /> </div> </el-col> <el-col :span="8"> <div class="field"> <div class="field-label">免费金币</div> <el-input v-model="addConsume.freeGold" disabled /> </div> </el-col> <el-col :span="8"> <div class="field"> <div class="field-label">任务金币</div> <el-input v-model="addConsume.taskGold" disabled /> </div> </el-col>
</el-row> <!-- 风险提示 --> <div style="display: flex; align-items: center; margin-top: 20px;"> <el-icon :size="24" color="#FFD700"> <WarnTriangleFilled /> </el-icon> <p>重复购买风险提示</p> </div> <!-- 记录 + 虚线分隔 --> <div> <el-divider border-style="dashed" /> <p>检测到该用户近期有相似消费记录:</p> · {{ ReadCookiesTime }} 购买 【{{ addConsume.goodsName.value }}】(操作人: {{ adminData.adminName }}) </div> <div style="margin-top: 10px"> <p>是否继续操作?</p>
</div> </div>
<!-- 底部按钮(居中) --> <template #footer> <div class="dialog-footer-center"> <el-button @click="ConsumeDialogVisibleCancel">取 消</el-button> <el-button type="primary" @click="ConsumeDialogVisibleContinue">确认购买</el-button> </div> </template> </el-dialog>
</div> </div> </template>
<style scoped lang="scss"> p { margin: 0px; }
/* 上传图片的格式 */ .avatar-uploader .avatar { width: 50px; height: 50px; display: block; }
.add-form { width: 400px; float: left; }
/* 标题居中 */ .el-dialog__header { text-align: center; }
.confirm-body { width: 350px; margin: 0 auto; }
/* 字段块与标签样式 */ .field { margin-bottom: 14px; }
.field-label { font-size: 14px; color: #606266; margin-bottom: 6px; }
/* 金币行紧凑 */ .coins-row .field { margin-bottom: 0; }
/* 底部按钮居中 */ .dialog-footer-center { display: flex; justify-content: center; gap: 12px; }
.father1 { width: 1000px; height: 100%; display: flex;
.left { width: 500px; float: left; display: flex; }
.right { flex: 1; height: 50vh; display: flex; align-items: center;
.customer-info { width: 300px; margin-left: 20px; display: flex; justify-content: center; align-items: center; } } } </style>
|