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.

985 lines
27 KiB

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