You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

968 lines
28 KiB

3 months ago
3 months ago
3 months ago
3 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 weeks ago
3 months ago
2 months ago
2 weeks ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. <script setup>
  2. import {onMounted, reactive, ref} from 'vue'
  3. import {ElIcon, ElMessage, ElMessageBox} from 'element-plus'
  4. import {Plus, WarnTriangleFilled} from '@element-plus/icons-vue'
  5. import axios from 'axios'
  6. import API from '@/util/http.js'
  7. import moment from 'moment'
  8. import Cookies from 'js-cookie';
  9. import Decimal from 'decimal.js';
  10. // 定义 fixedAdminId
  11. // const fixedAdminId = 1;
  12. // 精网号去空格
  13. const trimJwCode = () => {
  14. if (recharge.value.jwcode) {
  15. recharge.value.jwcode = recharge.value.jwcode.replace(/\s/g, '');
  16. }
  17. }
  18. // 上传图片前的验证函数
  19. const beforeAvatarUpload = (file) => {
  20. const validTypes = ['image/jpeg', 'image/png'];
  21. const isImage = validTypes.includes(file.type);
  22. const isLt1M = file.size / 1024 / 1024 < 1;
  23. if (!isImage) {
  24. ElMessage.error('只能上传 JPG/PNG 图片!');
  25. return false;
  26. }
  27. if (!isLt1M) {
  28. ElMessage.error('图片大小不能超过 1MB!');
  29. return false;
  30. }
  31. return true;
  32. };
  33. // 这是添加上传图片的接口
  34. const imageUrl = ref('')
  35. const voucher = ref('')
  36. // const rateName = ref()
  37. const adminData = ref({})
  38. // 获取管理员信息
  39. const getAdminData = async function () {
  40. try {
  41. const result = await API({
  42. url: '/admin/userinfo',
  43. data: {}
  44. })
  45. adminData.value = result
  46. recharge.value.adminId = adminData.value.id
  47. recharge.value.market = adminData.value.market
  48. console.log('请求成功', result)
  49. console.log('用户信息', user.value)
  50. } catch (error) {
  51. console.log('请求失败', error)
  52. }
  53. }
  54. //提交禁止重复点击
  55. const addDisabled = ref(false)
  56. // 这是添加充值信息的表单
  57. const recharge = ref({
  58. jwcode: '', // jwcode 字段
  59. activity: '', // activity 字段
  60. voucher: '',
  61. rechargeWay: '客服充值',
  62. freeGold: "",
  63. money: null,
  64. permanentGold: "",
  65. rateName: null,
  66. rateId: null,
  67. payModel: '', // payModel 字段
  68. payTime: null, // payTime 字段
  69. remark: '', // remark 字段
  70. rechargeRatio: ''
  71. })
  72. // 用来写的 cookie 的 key
  73. const WriteCookies = ref(null)
  74. // 用来写的 cookie 的 value
  75. const WriteCookiesTime = ref(null)
  76. // 用来读的 cookie 的 key
  77. const ReadCookies = ref(null)
  78. // 用来读的 cookie 的 value
  79. const ReadCookiesTime = ref(null)
  80. // 这是添加充值信息的接口
  81. const add = async function () {
  82. try {
  83. const formattedRecharge = {...recharge.value}
  84. // 将永久金币数、免费金币数和充值金额数乘以 100
  85. if (formattedRecharge.permanentGold) {
  86. formattedRecharge.permanentGold = Number(formattedRecharge.permanentGold) * 100;
  87. }
  88. if (formattedRecharge.freeGold) {
  89. formattedRecharge.freeGold = Number(formattedRecharge.freeGold) * 100;
  90. }
  91. if (formattedRecharge.money) {
  92. formattedRecharge.money = new Decimal(formattedRecharge.money).mul(100).toNumber();
  93. }
  94. if (formattedRecharge.payTime) {
  95. // 使用 moment.js 格式化 payTime
  96. formattedRecharge.payTime = moment(formattedRecharge.payTime).format('YYYY-MM-DD HH:mm:ss')
  97. }
  98. console.log('开始添加充值信息', recharge.value)
  99. //存一下 用户的jwcode
  100. // 拼接 jwcode:permanentGold:freeGold
  101. WriteCookies.value = `coinRecharge:${recharge.value.jwcode}:${recharge.value.permanentGold}:${recharge.value.freeGold}`
  102. //value 为充值时间
  103. WriteCookiesTime.value = recharge.value.payTime
  104. // 设置cookies,用户jwcode为key,value也是jwcode,过期时间为1天
  105. Cookies.set(WriteCookies.value, WriteCookiesTime.value, {expires: 1, path: '/'});
  106. // 发送POST请求
  107. addDisabled.value = true
  108. const result = await API({
  109. url: '/recharge/add',
  110. data: formattedRecharge
  111. })
  112. addDisabled.value = false
  113. if (result.code === 0) {
  114. ElMessage.error(result.msg)
  115. return
  116. }
  117. // 将响应结果存储到响应式数据中
  118. console.log('请求成功', result)
  119. // 显示成功消息
  120. ElMessage.success('添加成功')
  121. // 重置表单
  122. deleteRecharge()
  123. user.value = {}
  124. } catch (error) {
  125. console.log('请求失败', error)
  126. // 在这里可以处理错误逻辑,比如显示错误提示等
  127. }
  128. }
  129. // 二次校验充值对话框显示状态
  130. const RechargeDialogVisible = ref(false);
  131. // 第一次弹窗
  132. const FirstRechargeDialogVisible = ref(false);
  133. // 关闭第一次对话框
  134. const FirstRechargeDialogVisiblehandleClose = () => {
  135. FirstRechargeDialogVisible.value = false;
  136. // 重置表单数据
  137. deleteRecharge()
  138. user.value = {}
  139. };
  140. // 关闭第二次对话框
  141. const RechargeDialogVisiblehandleClose = () => {
  142. RechargeDialogVisible.value = false;
  143. // 重置表单数据
  144. deleteRecharge()
  145. user.value = {}
  146. };
  147. // 确认使用cookie继续充值
  148. const RechargeDialogVisibleContinue = () => {
  149. RechargeDialogVisible.value = false;
  150. add();
  151. };
  152. const RechargeDialogVisibleCancel = () => {
  153. RechargeDialogVisible.value = false
  154. deleteRecharge()
  155. user.value = {}
  156. };
  157. // 第一次实际执行充值操作
  158. // const proceedWithRecharge = () => {
  159. // FirstRechargeDialogVisible.value = false
  160. // add()
  161. // };
  162. const FistRechargeDialogVisibleContinue = () => {
  163. FirstRechargeDialogVisible.value = false
  164. add()
  165. };
  166. // 第一次取消
  167. const FirstRechargeDialogVisibleCancel = () => {
  168. FirstRechargeDialogVisible.value = false
  169. deleteRecharge()
  170. user.value = {}
  171. };
  172. // 添加充值信息前的按钮点击事件,进行表单验证和用户确认操作
  173. const addBefore = () => {
  174. // 为未输入的金币字段设置默认值
  175. if (!recharge.value.permanentGold) {
  176. recharge.value.permanentGold = '0';
  177. }
  178. if (!recharge.value.freeGold) {
  179. recharge.value.freeGold = '0';
  180. }
  181. // 表单验证
  182. Ref.value.validate(async (valid) => {
  183. if (!valid) {
  184. ElMessage({
  185. type: 'error',
  186. message: '请检查输入内容'
  187. });
  188. return;
  189. }
  190. // 验证金币不能同时为0
  191. if (Number(recharge.value.permanentGold) === 0 && Number(recharge.value.freeGold) === 0) {
  192. ElMessage({
  193. type: 'error',
  194. message: '永久金币和免费金币不能同时为0'
  195. });
  196. return;
  197. }
  198. // 验证币种选择
  199. if (!recharge.value.rateName) {
  200. ElMessage({
  201. type: 'error',
  202. message: '请选择币种'
  203. });
  204. return;
  205. }
  206. // 验证充值金额
  207. if (!recharge.value.money) {
  208. ElMessage({
  209. type: 'error',
  210. message: '请输入充值金额'
  211. });
  212. return;
  213. }
  214. // 设置对应的rateId,传负载用的
  215. const selectedRate = rateName.value.find(item => item.value === recharge.value.rateName);
  216. if (selectedRate) {
  217. recharge.value.rateId = selectedRate.value;
  218. recharge.value.rateName = selectedRate.label; // 将rateName设置为货币名称
  219. }
  220. // 检查是否有用户信息
  221. if (!user.value.jwcode) {
  222. ElMessage.warning('请先查询用户信息')
  223. return
  224. }
  225. // 检查cookie
  226. // 拼接 jwcode:permanentGold:freeGold
  227. ReadCookies.value = `coinRecharge:${recharge.value.jwcode}:${recharge.value.permanentGold}:${recharge.value.freeGold}`
  228. // 获取cookie
  229. const cookie = Cookies.get(ReadCookies.value)
  230. console.log("time", WriteCookiesTime.value)
  231. // 格式化时间
  232. ReadCookiesTime.value = moment(cookie).format('YYYY-MM-DD HH:mm:ss')
  233. console.log('cookie', cookie)
  234. // 如果存在cookie,显示确认对话框;否则直接进入充值确认
  235. if (cookie) {
  236. RechargeDialogVisible.value = true;
  237. } else {
  238. FirstRechargeDialogVisible.value = true;
  239. }
  240. });
  241. };
  242. // 表单验证
  243. // 开始时间改变时,重新验证结束时间
  244. const Ref = ref(null)
  245. const rules = reactive({
  246. jwcode: [{
  247. required: true, validator: (rule, value, callback) => {
  248. if (!value) {
  249. callback(new Error('精网号不能为空'));
  250. return;
  251. }
  252. if (/[^0-9]/.test(value)) {
  253. callback(new Error('精网号只能包含数字'));
  254. return;
  255. }
  256. callback();
  257. }, trigger: 'blur'
  258. }],
  259. activity: [{required: true, message: '请输入活动名称', trigger: 'blur'}],
  260. permanentGold: [
  261. {required: true, message: '请输入永久金币数', trigger: 'change'},
  262. {
  263. validator: (rule, value, callback) => {
  264. if (!value) {
  265. value = '0'
  266. }
  267. // 检查是否包含特殊符号
  268. if (/[^0-9.]/.test(value)) {
  269. callback(new Error('不能包含特殊符号或负数'));
  270. return;
  271. }
  272. // 检查整数位数
  273. const integerPart = value.split('.')[0];
  274. if (integerPart.length > 6) {
  275. callback(new Error('整数位数不能超过6位'));
  276. return;
  277. }
  278. // 检查小数位数
  279. if (value.includes('.')) {
  280. const decimalPart = value.split('.')[1];
  281. if (decimalPart.length > 2) {
  282. callback(new Error('小数位数不能超过两位'));
  283. return;
  284. }
  285. }
  286. const numValue = Number(value);
  287. if (isNaN(numValue)) {
  288. callback(new Error('请输入有效的数字'));
  289. } else if (numValue < 0) {
  290. callback(new Error('输入金额不能小于0'));
  291. } else {
  292. callback();
  293. }
  294. },
  295. trigger: 'blur'
  296. }
  297. ],
  298. freeGold: [
  299. {required: true, message: '请输入免费金币数', trigger: 'change'},
  300. {
  301. validator: (rule, value, callback) => {
  302. if (!value) {
  303. value = '0'
  304. }
  305. // 检查是否包含特殊符号
  306. if (/[^0-9.]/.test(value)) {
  307. callback(new Error('不能包含特殊符号或负数'));
  308. return;
  309. }
  310. // 检查整数位数
  311. const integerPart = value.split('.')[0];
  312. if (integerPart.length > 6) {
  313. callback(new Error('整数位数不能超过6位'));
  314. return;
  315. }
  316. // 检查小数位数
  317. if (value.includes('.')) {
  318. const decimalPart = value.split('.')[1];
  319. if (decimalPart.length > 2) {
  320. callback(new Error('小数位数不能超过两位'));
  321. return;
  322. }
  323. }
  324. const numValue = Number(value);
  325. if (isNaN(numValue)) {
  326. callback(new Error('请输入有效的数字'));
  327. } else if (numValue < 0) {
  328. callback(new Error('输入金额不能小于0'));
  329. } else {
  330. callback();
  331. }
  332. },
  333. trigger: 'blur'
  334. }
  335. ],
  336. rateName: [{
  337. required: true,
  338. message: '请选择货币名称',
  339. trigger: 'blur'
  340. }],
  341. money: [
  342. {required: true, message: '请输入充值金额', trigger: 'blur'},
  343. {
  344. validator: (rule, value, callback) => {
  345. // 检查是否包含特殊符号
  346. if (/[^0-9.]/.test(value)) {
  347. callback(new Error('不能包含特殊符号或负数'));
  348. return;
  349. }
  350. // 检查整数位数
  351. const integerPart = value.split('.')[0];
  352. if (integerPart.length > 6) {
  353. callback(new Error('整数位数不能超过6位'));
  354. return;
  355. }
  356. // 检查小数位数
  357. if (value.includes('.')) {
  358. const decimalPart = value.split('.')[1];
  359. if (decimalPart.length > 2) {
  360. callback(new Error('小数位数不能超过两位'));
  361. return;
  362. }
  363. }
  364. const numValue = Number(value);
  365. if (isNaN(numValue)) {
  366. callback(new Error('请输入有效的数字'));
  367. } else if (numValue < 0) {
  368. callback(new Error('输入金额不能小于0'));
  369. } else {
  370. callback();
  371. }
  372. },
  373. trigger: 'blur'
  374. }
  375. ],
  376. payModel: [{required: true, message: '请选择付款方式', trigger: 'blur'}],
  377. payTime: [{required: true, message: '请选择交款时间', trigger: 'blur'}]
  378. });
  379. // 查找客户信息的方法
  380. const user = ref({})
  381. const getUser = async function (jwcode) {
  382. trimJwCode();
  383. // 验证精网号
  384. if (!jwcode) {
  385. ElMessage.warning('精网号不能为空');
  386. return;
  387. }
  388. // 验证精网号是否为数字
  389. if (!/^\d{1,9}$/.test(jwcode)) {
  390. ElMessage.warning('精网号必须为数字且不超过九位');
  391. deleteRecharge()
  392. return;
  393. }
  394. try {
  395. const result = await API({
  396. url: '/user/selectUser',
  397. data: {
  398. jwcode: recharge.value.jwcode
  399. }
  400. })
  401. if (result.code === 0) {
  402. ElMessage.error(result.msg);
  403. } else if (result.data === null) {
  404. ElMessage.error("用户不存在");
  405. } else {
  406. user.value = result.data;
  407. console.log("用户信息", user.value);
  408. ElMessage.success("查询成功");
  409. }
  410. } catch (error) {
  411. console.log("请求失败", error);
  412. ElMessage.error("精网号错误");
  413. }
  414. }
  415. // 这是查询活动的接口,一期没有调用这个接口
  416. const activity = ref([])
  417. // const getActivity = async function () {
  418. // try {
  419. // // 发送POST请求
  420. // const result = await API({
  421. // url: '/general/activity',
  422. // data: {
  423. // }
  424. // })
  425. // // 将响应结果存储到响应式数据中
  426. // console.log('请求成功', result)
  427. // // 存储表格数据
  428. // activity.value = result.data
  429. // console.log('活动信息', activity.value)
  430. // } catch (error) {
  431. // console.log('activity请求失败', error)
  432. // // 在这里可以处理错误逻辑,比如显示错误提示等
  433. // }
  434. // }
  435. //货币条目
  436. const rateName = ref([])
  437. const fetchRateData = async () => {
  438. try {
  439. const result = await API({
  440. url: '/general/getRate',
  441. data: {}
  442. });
  443. console.log('response', result);
  444. if (result.code === 200) {
  445. rateName.value = result.data.map(item => ({
  446. value: item.id,
  447. label: item.rateName,
  448. }));
  449. }
  450. console.log('货币信息', rateName.value);
  451. } catch (error) {
  452. console.error('获取货币信息失败:', error);
  453. }
  454. };
  455. // 修改上传处理
  456. const customUpload = async (options) => {
  457. try {
  458. const formData = new FormData();
  459. formData.append('file', options.file);
  460. const response = await axios.post(import.meta.env.VITE_UPLOAD_URL, formData, {
  461. headers: {
  462. 'Content-Type': 'multipart/form-data',
  463. 'Authorization': `Bearer ${localStorage.getItem('token')}`
  464. }
  465. });
  466. if (response.data.code === 200 && response.data.data) {
  467. // 传递原始文件对象和响应数据
  468. handleAvatarSuccess(response.data, options.file);
  469. ElMessage.success('上传成功');
  470. } else {
  471. ElMessage.error(response.data.msg || '上传失败');
  472. }
  473. } catch (error) {
  474. console.error('上传错误:', error);
  475. ElMessage.error(`上传失败: ${error.response?.data?.message || error.message}`);
  476. }
  477. };
  478. // 获取环境变量
  479. // const uploadUrl = import.meta.env.VITE_UPLOAD_URL;
  480. // 上传图片成功的回调函数
  481. const handleAvatarSuccess = (response, file) => {
  482. // 直接使用 file 对象创建 Object URL
  483. imageUrl.value = URL.createObjectURL(file);
  484. // 使用服务器返回的文件路径(根据实际响应结构调整)
  485. if (response && response.filePath) {
  486. recharge.value.voucher = response.filePath;
  487. } else if (response && response.url) {
  488. recharge.value.voucher = response.url;
  489. } else if (response && response.data) {
  490. // 假设响应结构为 { code: 200, data: { filePath: ... } }
  491. recharge.value.voucher = response.data.filePath || response.data.url;
  492. } else {
  493. // 后备方案:使用环境变量中的上传URL
  494. recharge.value.voucher = import.meta.env.VITE_UPLOAD_URL;
  495. }
  496. }
  497. //支付方式条目
  498. const payModel = [
  499. {
  500. value: '银行转账',
  501. label: '银行转账'
  502. },
  503. {
  504. value: '现金',
  505. label: '现金'
  506. },
  507. {
  508. value: '支票',
  509. label: '支票'
  510. },
  511. {
  512. value: '刷卡',
  513. label: '刷卡'
  514. },
  515. {
  516. value: 'Grabpay',
  517. label: 'Grabpay'
  518. },
  519. {
  520. value: 'Nets',
  521. label: 'Nets'
  522. },
  523. {
  524. value: 'PayPal',
  525. label: 'PayPal'
  526. },
  527. {
  528. value: 'Stripe-链接收款',
  529. label: 'Stripe-链接收款'
  530. },
  531. {
  532. value: 'Ipay88-链接收款',
  533. label: 'Ipay88-链接收款'
  534. },
  535. {
  536. value: 'PaymentAsia-链接收款',
  537. label: 'PaymentAsia-链接收款'
  538. },
  539. {
  540. value: '其他',
  541. label: '其他'
  542. }
  543. ]
  544. // // }
  545. // function handleActivityChange(value) {
  546. // // 在这里执行逻辑,例如获取选中的值
  547. // console.log('选中的值:', value)
  548. // // getActivityById(value)
  549. // console.log('看看', recharge.value)
  550. // }
  551. //这是重置重置表单的方法
  552. const deleteRecharge = function () {
  553. Ref.value.resetFields();
  554. recharge.value = {
  555. adminId: adminData.value.id,
  556. //adminId: fixedAdminId,
  557. market: adminData.value.market,
  558. voucher: '',
  559. rechargeWay: '客服充值',
  560. freeGold: '',
  561. money: null,
  562. permanentGold: '',
  563. rateId: null
  564. }
  565. imageUrl.value = ''
  566. recharge.value.rateName = ''
  567. }
  568. onMounted(async function () {
  569. await getAdminData()
  570. await fetchRateData()
  571. // await getCurrency()
  572. // await getActivity()// 现在的活动就是文字输入框,不需要请求接口,具体等后续需求
  573. })
  574. onMounted(() => {
  575. console.log('上传URL:', import.meta.env.VITE_UPLOAD_URL);
  576. });
  577. </script>
  578. <template>
  579. <div>
  580. <div class="userAndForm">
  581. <div class="left">
  582. <el-form :model="recharge" ref="Ref" :rules="rules" label-width="auto" label-position="right"
  583. style="min-width: 420px" class="add-form">
  584. <el-form-item prop="jwcode" label="精网号">
  585. <el-input v-model="recharge.jwcode" style="width: 220px"/>
  586. <el-button type="primary" @click="getUser(recharge.jwcode)" style="margin-left: 20px">查询</el-button>
  587. </el-form-item>
  588. <el-form-item prop="activity" label="活动名称">
  589. <el-input v-model="recharge.activity" placeholder="请输入活动名称" style="width: 300px"/>
  590. </el-form-item>
  591. <el-form-item prop="permanentGold" label="永久金币">
  592. <el-input v-model="recharge.permanentGold" placeholder="0" style="width: 100px"/>
  593. <p>&nbsp;</p>
  594. </el-form-item>
  595. <el-form-item prop="freeGold" label="免费金币">
  596. <el-input v-model="recharge.freeGold" placeholder="0" style="width: 100px"/>
  597. <p>&nbsp;</p>
  598. </el-form-item>
  599. <el-form-item label="充值金额" required>
  600. <el-form-item prop="rateName" style="display: inline-block; margin-left:0;">
  601. <el-select v-model="recharge.rateName" placeholder="货币名称" style="width: 100px">
  602. <el-option v-for="item in rateName" :key="item.value" :label="item.label" :value="item.value"/>
  603. </el-select>
  604. </el-form-item>
  605. <el-form-item prop="money" style="display: inline-block; margin-left:10px;">
  606. <el-input v-model="recharge.money" style="width: 190px"/>
  607. </el-form-item>
  608. </el-form-item>
  609. <el-form-item prop="payModel" label="收款方式">
  610. <el-select v-model="recharge.payModel" placeholder="请选择" style="width: 300px">
  611. <el-option v-for="item in payModel" :key="item.value" :label="item.label" :value="item.value"/>
  612. </el-select>
  613. </el-form-item>
  614. <el-form-item prop="payTime" label="交款时间">
  615. <!-- 修改 type 属性为 datetime 以支持时分秒选择 -->
  616. <el-date-picker v-model="recharge.payTime" type="datetime" style="width: 300px"/>
  617. </el-form-item>
  618. <el-form-item prop="voucher" label="交款凭证" style="margin-bottom: 5px">
  619. <el-upload :http-request="customUpload" class="avatar-uploader" :show-file-list="false"
  620. :before-upload="beforeAvatarUpload" style="width: 100px; height: 115px">
  621. <img v-if="imageUrl" :src="imageUrl" class="avatar" style="width: 100px; height: 115px"/>
  622. <el-icon v-else class="avatar-uploader-icon" style="width: 100px; height: 100px">
  623. <Plus/>
  624. </el-icon>
  625. </el-upload>
  626. <p style="margin-left: 10px; color: rgb(177, 176, 176)">
  627. 仅支持.jpg .png格式文件1MB
  628. </p>
  629. </el-form-item>
  630. <el-form-item prop="remark" label="备注">
  631. <el-input v-model="recharge.remark" style="width: 300px" :rows="4" maxlength="100" show-word-limit
  632. type="textarea"/>
  633. </el-form-item>
  634. <el-button @click="deleteRecharge" style="margin-left: 220px;margin-top:20px" type="success">重置</el-button>
  635. <el-button type="primary" style="margin-top:20px" :disabled="addDisabled" @click="addBefore"> 提交</el-button>
  636. </el-form>
  637. </div>
  638. <div class="right">
  639. <!-- 客户信息栏 -->
  640. <el-card v-if="user.jwcode" style="width: 800px; float: right" class="customer-info">
  641. <el-form :model="user" label-width="auto" style="max-width: 1000px" label-position="left">
  642. <el-text size="large" style="margin-left: 20px">客户信息</el-text>
  643. <!-- 第一行姓名 + 历史金币 -->
  644. <el-row style="margin-top: 20px">
  645. <el-col :span="9">
  646. <el-form-item label="姓名">
  647. <p>{{ user.name }}</p>
  648. </el-form-item>
  649. </el-col>
  650. <el-col :span="14">
  651. <el-form-item label="当前金币总数" style="width: 500px">
  652. <span style="color: #2fa1ff; margin-right: 5px" v-if="user.nowSumGold !== undefined">{{
  653. user.nowSumGold
  654. }}</span>
  655. </el-form-item>
  656. <!-- 金币详情独立显示 -->
  657. <el-form-item style="margin-top: -23px"> <!-- 负边距减少间距 -->
  658. <span style="color: #b1b1b1; margin-left: 0px" v-if="user.nowPermanentGold !== undefined">(永久金币:{{
  659. user.nowPermanentGold
  660. }};
  661. 免费金币:{{ user.nowFreeGold }};
  662. 任务金币:{{ user.nowTaskGold }})</span>
  663. </el-form-item>
  664. </el-col>
  665. </el-row>
  666. <!-- 第二行精网号 + 当前金币独立行 -->
  667. <el-row>
  668. <el-col :span="9">
  669. <el-form-item label="精网号">
  670. <p>{{ user.jwcode }}</p>
  671. </el-form-item>
  672. </el-col>
  673. <el-col :span="14">
  674. <el-form-item label="消费次数">
  675. <p style="color: #2fa1ff">{{ user.consumeNum }} </p>
  676. </el-form-item>
  677. <el-form-item style="margin-top: -23px"> <!-- 负边距减少间距 -->
  678. <p style="font-size: small; color: #b1b1b1">(仅统计2025-01-01后的数据)</p>
  679. </el-form-item>
  680. </el-col>
  681. </el-row>
  682. <!-- 第三行首次充值日期 + 充值次数 -->
  683. <!-- <el-row >
  684. <el-col :span="9">
  685. <el-form-item label="首次充值日期">
  686. <p v-if="user.firstRecharge">
  687. {{ moment(user.firstRecharge).format('YYYY-MM-DD HH:mm:ss') }}
  688. </p>
  689. </el-form-item>
  690. </el-col>
  691. </el-row> -->
  692. <!-- 第四行消费次数 + 所属门店 -->
  693. <el-row>
  694. <el-col :span="9">
  695. <el-form-item label="所属门店">
  696. <p>{{ user.market }}</p>
  697. </el-form-item>
  698. </el-col>
  699. </el-row>
  700. </el-form>
  701. </el-card>
  702. </div>
  703. </div>
  704. <el-dialog v-model="FirstRechargeDialogVisible" title="操作确认"
  705. :before-close="FirstRechargeDialogVisiblehandleClose"
  706. :close-on-click-modal="false" width="400px">
  707. <!-- 内容整体居中且收窄 -->
  708. <div class="confirm-body">
  709. <!-- 用户信息 -->
  710. <div>
  711. <div class="field-label">用户信息</div>
  712. <el-input :model-value="user.jwcode + (user.name ? '' + user.name + '' : '')" disabled/>
  713. </div>
  714. <!-- 活动名称 -->
  715. <div class="field">
  716. <div class="field-label">活动名称</div>
  717. <el-input v-model="recharge.activity" disabled/>
  718. </div>
  719. <!-- 金币信息同一行左右排列 -->
  720. <el-row :gutter="20" class="coins-row">
  721. <el-col :span="12">
  722. <div class="field">
  723. <div class="field-label">永久金币</div>
  724. <el-input v-model="recharge.permanentGold" disabled/>
  725. </div>
  726. </el-col>
  727. <el-col :span="12">
  728. <div class="field">
  729. <div class="field-label">免费金币</div>
  730. <el-input v-model="recharge.freeGold" disabled/>
  731. </div>
  732. </el-col>
  733. </el-row>
  734. <div class="field">
  735. <div class="field-label">备注</div>
  736. <el-input v-model="recharge.remark" disabled/>
  737. </div>
  738. </div>
  739. <!-- 底部按钮居中 -->
  740. <template #footer>
  741. <div class="dialog-footer-center">
  742. <el-button @click="FirstRechargeDialogVisibleCancel"> </el-button>
  743. <el-button type="primary" @click="FistRechargeDialogVisibleContinue">确认充值</el-button>
  744. </div>
  745. </template>
  746. </el-dialog>
  747. <el-dialog v-model="RechargeDialogVisible" title="操作确认" :before-close="RechargeDialogVisiblehandleClose"
  748. :close-on-click-modal="false" width="480px">
  749. <!-- 内容整体居中且收窄 -->
  750. <div class="confirm-body">
  751. <!-- 用户信息 -->
  752. <div>
  753. <div class="field-label">用户信息</div>
  754. <el-input :model-value="user.jwcode + (user.name ? '' + user.name + '' : '')" disabled/>
  755. </div>
  756. <!-- 活动名称 -->
  757. <div class="field">
  758. <div class="field-label">活动名称</div>
  759. <el-input v-model="recharge.activity" disabled/>
  760. </div>
  761. <!-- 金币信息同一行左右排列 -->
  762. <el-row :gutter="20" class="coins-row">
  763. <el-col :span="12">
  764. <div class="field">
  765. <div class="field-label">永久金币</div>
  766. <el-input v-model="recharge.permanentGold" disabled/>
  767. </div>
  768. </el-col>
  769. <el-col :span="12">
  770. <div class="field">
  771. <div class="field-label">免费金币</div>
  772. <el-input v-model="recharge.freeGold" disabled/>
  773. </div>
  774. </el-col>
  775. </el-row>
  776. <!-- 风险提示 -->
  777. <div style="display: flex; align-items: center; margin-top: 20px;">
  778. <el-icon :size="24" color="#FFD700">
  779. <WarnTriangleFilled/>
  780. </el-icon>
  781. <p>重复充值风险提示</p>
  782. </div>
  783. <!-- 记录 + 虚线分隔 -->
  784. <div>
  785. <el-divider border-style="dashed"/>
  786. <p>检测到该用户近期有相似充值记录</p>
  787. · {{ ReadCookiesTime }} 充值永久金币: {{ recharge.permanentGold }}
  788. 免费金币: {{ recharge.freeGold }}(操作人{{ adminData.adminName }})
  789. </div>
  790. <div style="margin-top: 10px">
  791. <p>是否继续操作</p>
  792. </div>
  793. </div>
  794. <!-- 底部按钮居中 -->
  795. <template #footer>
  796. <div class="dialog-footer-center">
  797. <el-button @click="RechargeDialogVisibleCancel"> </el-button>
  798. <el-button type="primary" @click="RechargeDialogVisibleContinue">确认充值</el-button>
  799. </div>
  800. </template>
  801. </el-dialog>
  802. </div>
  803. </template>
  804. <style scoped lang="scss">
  805. .userAndForm {
  806. width: 1150px;
  807. height: 100%;
  808. display: flex;
  809. align-items: center;
  810. .left {
  811. width: 35%;
  812. display: flex;
  813. .add-form {
  814. width: 100%;
  815. margin-top: 50px;
  816. }
  817. }
  818. .right {
  819. flex: 1;
  820. margin-left: 20px;
  821. display: flex;
  822. .customer-info{
  823. width: 90%;
  824. display: flex;
  825. margin-left: 20px;
  826. justify-content: center;
  827. align-items: center;
  828. padding: 0 10px;
  829. }
  830. }
  831. }
  832. p {
  833. margin: 0px;
  834. }
  835. // .batch-btn {
  836. // margin-top: 20px;
  837. // margin-left: auto;
  838. // }
  839. .field-label {
  840. font-size: 14px;
  841. color: #606266;
  842. margin-bottom: 6px;
  843. }
  844. /* 金币行紧凑 */
  845. .coins-row .field {
  846. margin-bottom: 0;
  847. }
  848. /* 底部按钮居中 */
  849. .dialog-footer-center {
  850. display: flex;
  851. justify-content: center;
  852. gap: 12px;
  853. }
  854. :deep(.avatar-uploader .avatar) {
  855. width: 50px;
  856. height: 50px;
  857. display: block;
  858. }
  859. :deep(.avatar-uploader .el-upload) {
  860. border: 1px dashed var(--el-border-color);
  861. border-radius: 6px;
  862. cursor: pointer;
  863. position: relative;
  864. overflow: hidden;
  865. transition: var(--el-transition-duration-fast);
  866. }
  867. :deep(.avatar-uploader .el-upload:hover) {
  868. border-color: var(--el-color-primary);
  869. }
  870. :deep(.el-icon.avatar-uploader-icon) {
  871. font-size: 28px;
  872. color: #8c939d;
  873. width: 50px;
  874. height: 50px;
  875. text-align: center;
  876. }
  877. </style>