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.

599 lines
17 KiB

  1. <script setup>
  2. import { onMounted, reactive } from 'vue'
  3. import { ref, computed, watch } from 'vue'
  4. import { ElMessage } from 'element-plus'
  5. import { Plus } from '@element-plus/icons-vue'
  6. import axios from 'axios'
  7. import { ElMessageBox } from 'element-plus'
  8. import API from '@/util/http'
  9. import moment from 'moment'
  10. // import _ from 'lodash'
  11. const addRe = ref({
  12. typeR: '0'
  13. })
  14. //这是获取用户信息的接口
  15. const adminData = ref({})
  16. const getAdminData = async function () {
  17. try {
  18. const result = await API({ url: '/admin/userinfo', data: {} })
  19. adminData.value = result
  20. addRefund.value.adminId = adminData.value.adminId
  21. console.log('请求成功', result)
  22. console.log('用户信息', user.value)
  23. } catch (error) {
  24. console.log('请求失败', error)
  25. }
  26. }
  27. // 精网号去空格
  28. const trimJwCode = () => {
  29. if (addRefund.value.jwcode) {
  30. addRefund.value.jwcode = addRefund.value.jwcode.replace(/\s/g, '');
  31. }
  32. }
  33. // 这是添加退款信息的表单
  34. const addRefund = ref({
  35. jwcode: '',
  36. goodsName: '',
  37. refundType: '',
  38. refundModel: 0,
  39. permanentGold: '',
  40. freeGold: '',
  41. taskGold: '',
  42. sumGold: 0,
  43. remark: '',
  44. adminId: null
  45. })
  46. // 取消按钮
  47. const cancel = function () {
  48. addRefund.value = {
  49. jwcode: '',
  50. goodsName: '',
  51. refundType: '',
  52. refundModel: 0,
  53. permanentGold: '',
  54. freeGold: '',
  55. taskGold: '',
  56. sumGold: 0,
  57. remark: '',
  58. adminId: adminData.value.adminId
  59. }
  60. addRe.value.typeR = '0'
  61. }
  62. // 这是添加退款信息的接口
  63. const add = async function () {
  64. try {
  65. // 更新 refundModel
  66. addRefund.value.refundModel = parseInt(addRe.value.typeR);
  67. // 对提交的金币数乘以 100
  68. const processedRefund = {
  69. ...addRefund.value,
  70. permanentGold: (Number(addRefund.value.permanentGold) || 0) * 100,
  71. freeGold: (Number(addRefund.value.freeGold) || 0) * 100,
  72. taskGold: (Number(addRefund.value.taskGold) || 0) * 100,
  73. sumGold: (Number(addRefund.value.sumGold) || 0) * 100,
  74. adminId: 1
  75. }
  76. // 发送POST请求
  77. const result = await API({ url: 'http://18.143.76.3:10704/refund/add',
  78. data: processedRefund
  79. })
  80. if (result.code === 0) {
  81. ElMessage.error(result.msg)
  82. return
  83. }
  84. console.log('请求成功', result)
  85. ElMessage.success('添加成功')
  86. // 重置表单
  87. cancel()
  88. } catch (error) {
  89. console.log('请求失败', error)
  90. // 在这里可以处理错误逻辑,比如显示错误提示等
  91. }
  92. }
  93. // 提交退款信息前的表单验证
  94. const addBefore = () => {
  95. Ref.value.validate(async (valid) => {
  96. if (valid) {
  97. ElMessageBox.confirm('确认添加?')
  98. .then(() => {
  99. add()
  100. console.log('添加成功')
  101. })
  102. .catch(() => {
  103. console.log('取消添加')
  104. })
  105. } else {
  106. //提示
  107. ElMessage({
  108. type: 'error',
  109. message: '请检查输入内容'
  110. })
  111. }
  112. })
  113. }
  114. // 表单验证
  115. // 开始时间改变时,重新验证结束时间
  116. const Ref = ref(null)
  117. const startChange = (val) => {}
  118. const rules = reactive({
  119. jwcode: [{ required: true, message: '请输入精网号', trigger: 'blur' }],
  120. refundType: [{ required: true, message: '请选择退款类型', trigger: 'blur' }],
  121. goodsName: [{ required: true, message: '请选择退款商品', trigger: 'blur' }],
  122. taskGold: [{ required: true, message: '请输入任务金币', trigger: 'blur' }],
  123. freeGold: [{ required: true, message: '请输入免费金币', trigger: 'blur' }],
  124. permanentGold: [
  125. { required: true, message: '请输入永久金币', trigger: 'blur' }
  126. ],
  127. sumGold: [
  128. { required: true, message: '请选择付款方式', trigger: 'blur' },
  129. {
  130. validator: (rule, value) => {
  131. if (value === 0) {
  132. return Promise.reject(new Error('总金币不能为0'))
  133. }
  134. return Promise.resolve()
  135. },
  136. trigger: 'blur'
  137. }
  138. ]
  139. })
  140. // 查找客户信息的方法
  141. const user = ref({
  142. firstRechargeTime: ''
  143. })
  144. const getUser = async function (jwcode) {
  145. trimJwCode();
  146. try {
  147. // 发送POST请求
  148. const result = await API({
  149. url: 'http://18.143.76.3:10704/user/selectUser',
  150. data: {
  151. jwcode: addRefund.value.jwcode
  152. }
  153. })
  154. console.log('请求成功', result)
  155. //在此处错误逻辑的提示做了注释,在后续商品查询接口返回错误时,提示信息会显示在弹窗中
  156. if (result.code === 0) {
  157. ElMessage.error(result.msg);
  158. } else if (result.data === null) {
  159. ElMessage.error("用户不存在");
  160. } else {
  161. // 对传过来的金币数除以 100
  162. const processedData = {
  163. ...result.data,
  164. historySumGold: (Number(result.data.historySumGold) || 0) / 100,
  165. nowSumGold: (Number(result.data.nowSumGold) || 0) / 100,
  166. nowPermanentGold: (Number(result.data.nowPermanentGold) || 0) / 100,
  167. nowFreeGold: (Number(result.data.nowFreeGold) || 0) / 100,
  168. nowTaskGold: (Number(result.data.nowTaskGold) || 0) / 100
  169. }
  170. user.value = processedData;
  171. console.log("用户信息", user.value);
  172. ElMessage.success(result.msg);
  173. }
  174. } catch (error) {
  175. console.log("请求失败", error);
  176. ElMessage.error("查询失败,请检查精网号是否正确");
  177. // 在这里可以处理错误逻辑,比如显示错误提示等
  178. }
  179. }
  180. // 退款类型
  181. const refundType = ref([])
  182. // 获取退款类型
  183. const getRefundTypes = async function () {
  184. try {
  185. // 发送请求获取退款类型
  186. const result = await API({
  187. url: 'http://18.143.76.3:10704/refund/refundType', //这里应该写上一个退款类型的接口
  188. data: {} })
  189. console.log('退款类型请求成功', result)
  190. // 检查返回的数据是否为数组
  191. if (Array.isArray(result.data)) {
  192. // 将字符串数组转换为 { value, label } 格式
  193. refundType.value = result.data.map(item => ({ value: item, label: item }));
  194. } else {
  195. console.error('退款类型数据格式错误', result)
  196. ElMessage.error('退款类型数据格式错误,请联系管理员')
  197. }
  198. console.log('退款类型', refundType.value)
  199. } catch (error) {
  200. console.log('退款类型请求失败', error)
  201. }
  202. }
  203. // 根据精网号查询商品
  204. const goodsName = ref([])
  205. const getGoods = async function (jwcode) {
  206. trimJwCode();
  207. // 只有精网号存在时才发送请求
  208. if (!addRefund.value.jwcode) {
  209. goodsName.value = []; // 清空商品数据
  210. return;
  211. }
  212. try {
  213. // 发送POST请求
  214. const result = await API({
  215. // url: 'http://39.101.133.168:8828/live_mall/api/product/all', //需要接口
  216. url: 'http://18.143.76.3:10704/refund/selectGoods',
  217. data: {
  218. jwcode: addRefund.value.jwcode
  219. }
  220. })
  221. console.log('请求成功', result)
  222. // 检查返回的数据是否为数组
  223. if (Array.isArray(result.data)) {
  224. // 将字符串数组转换为 { value, label } 格式
  225. goodsName.value = result.data.map(item => ({
  226. value: item.goodsName, // 使用商品名称作为 value
  227. label: item.goodsName,
  228. key: item.goodsName,
  229. // 保留其他字段
  230. permanentGold: (Number(item.permanentGold) || 0) / 100,
  231. freeGold: (Number(item.freeGold) || 0) / 100,
  232. taskGold: (Number(item.taskGold) || 0) / 100
  233. }));
  234. } else {
  235. console.error('退款类型数据格式错误', result)
  236. ElMessage.error('退款类型数据格式错误,请联系管理员')
  237. }
  238. } catch (error) {
  239. console.log('请求失败', error)
  240. ElMessage.error('查询商品失败,请检查精网号是否正确')
  241. goodsName.value = []; // 请求失败时清空商品数据
  242. }
  243. }
  244. // 存储选中商品的金币花费信息
  245. const selectedGoodsGold = ref({
  246. permanentGold: 0,
  247. freeGold: 0,
  248. taskGold: 0
  249. })
  250. const handleSelectionChange = (selectedOption) => {
  251. if (selectedOption) {
  252. // 更新商品名称
  253. addRefund.value.goodsName = selectedOption.value;
  254. // 更新金币字段
  255. addRefund.value.permanentGold = selectedOption.permanentGold || 0;
  256. addRefund.value.freeGold = selectedOption.freeGold || 0;
  257. addRefund.value.taskGold = selectedOption.taskGold || 0;
  258. // 记录选中商品的金币花费
  259. selectedGoodsGold.value.permanentGold = Number(selectedOption.permanentGold) || 0;
  260. selectedGoodsGold.value.freeGold = Number(selectedOption.freeGold) || 0;
  261. selectedGoodsGold.value.taskGold = Number(selectedOption.taskGold) || 0;
  262. } else {
  263. // 清空逻辑保持不变
  264. }
  265. console.log('选择的商品', selectedOption);
  266. }
  267. // 验证输入的金币数量是否超过商品花费的金币数量
  268. const validateGoldInput = (type, value) => {
  269. const maxValue = selectedGoodsGold.value[type];
  270. const inputValue = Number(value);
  271. if (isNaN(inputValue)) {
  272. return 0;
  273. }
  274. return Math.min(inputValue, maxValue);
  275. }
  276. // 处理永久金币输入
  277. const handlePermanentGoldInput = (value) => {
  278. addRefund.value.permanentGold = validateGoldInput('permanentGold', value);
  279. }
  280. // 处理免费金币输入
  281. const handleFreeGoldInput = (value) => {
  282. addRefund.value.freeGold = validateGoldInput('freeGold', value);
  283. }
  284. // 处理任务金币输入
  285. const handleTaskGoldInput = (value) => {
  286. addRefund.value.taskGold = validateGoldInput('taskGold', value);
  287. }
  288. // 计算总金币
  289. const calculatedRechargeGoods = computed(() => {
  290. const permanentGold = addRefund.value.permanentGold === '' ? 0 : +addRefund.value.permanentGold;
  291. const freeGold = addRefund.value.freeGold === '' ? 0 : +addRefund.value.freeGold;
  292. const taskGold = addRefund.value.taskGold === '' ? 0 : +addRefund.value.taskGold;
  293. return permanentGold + freeGold + taskGold;
  294. })
  295. watch(calculatedRechargeGoods, (newVal) => {
  296. addRefund.value.sumGold = newVal
  297. console.log('计算的总金币', newVal)
  298. })
  299. // 绑定两个数据
  300. // 挂载
  301. onMounted(async function () {
  302. await getAdminData()
  303. await getRefundTypes()
  304. // await getGoods()
  305. })
  306. </script>
  307. <template>
  308. <div >
  309. <el-form
  310. :model="addRefund"
  311. ref="Ref"
  312. :rules="rules"
  313. label-width="auto"
  314. style="max-width: 750px"
  315. class="form-style"
  316. >
  317. <el-form-item prop="jwcode" label="精网号">
  318. <el-input
  319. v-model="addRefund.jwcode"
  320. style="width: 220px"
  321. @change="getGoods(addRefund.jwcode)"
  322. />
  323. <el-button
  324. type="primary"
  325. @click="getUser(addRefund.jwcode)"
  326. style="margin-left: 20px"
  327. >查询</el-button
  328. >
  329. </el-form-item>
  330. <el-form-item prop="refundType" label="退款类型">
  331. <el-select
  332. v-model="addRefund.refundType"
  333. placeholder="请选择"
  334. style="width: 300px"
  335. >
  336. <el-option
  337. v-for="item in refundType"
  338. :key="item.value"
  339. :label="item.label"
  340. :value="item.value"
  341. />
  342. </el-select>
  343. </el-form-item>
  344. <el-form-item prop="goodsName" label="商品名">
  345. <el-select
  346. v-model="addRefund.goodsName"
  347. placeholder="请选择"
  348. style="width: 300px"
  349. @change="handleSelectionChange"
  350. >
  351. <el-option
  352. v-for="item in goodsName"
  353. :key="item.key"
  354. :label="item.label"
  355. :value="item"
  356. />
  357. </el-select>
  358. </el-form-item>
  359. <el-form-item prop="refundModel" label="退款方式:">
  360. <el-radio-group v-model="addRe.typeR">
  361. <el-radio value="0" @change="addRe.typeR = '0'">全部退款</el-radio>
  362. <el-radio value="1">部分退款</el-radio>
  363. </el-radio-group>
  364. </el-form-item>
  365. <div style="display: flex; align-items: center">
  366. <el-form-item prop="permanentGold" label="永久金币" style="float: left">
  367. <el-input
  368. v-model="addRefund.permanentGold"
  369. style="width: 100px"
  370. :disabled="addRe.typeR === '0' ? true : false"
  371. @input="handlePermanentGoldInput($event)"
  372. >
  373. </el-input>
  374. <p></p>
  375. </el-form-item>
  376. <el-form-item
  377. prop="freeGold"
  378. label="免费金币"
  379. style="margin-left: -20px; float: left"
  380. >
  381. <el-input
  382. v-model="addRefund.freeGold"
  383. style="float: left; width: 100px"
  384. :disabled="addRe.typeR === '0' ? true : false"
  385. @input="handleFreeGoldInput($event)"
  386. />
  387. <p></p>
  388. </el-form-item>
  389. <el-form-item prop="taskGold" label="任务金币" style="margin-left: -20px">
  390. <el-input
  391. v-model="addRefund.taskGold"
  392. style="float: left; width: 100px"
  393. :disabled="addRe.typeR === '0' ? true : false"
  394. @input="handleTaskGoldInput($event)"
  395. />
  396. <p></p>
  397. </el-form-item>
  398. </div>
  399. <el-form-item prop="sumGold" label="退款金币总数">
  400. <el-input disabled v-model="addRefund.sumGold" style="width: 100px">
  401. </el-input>
  402. </el-form-item>
  403. <el-form-item prop="remark" label="备注">
  404. <el-input
  405. v-model="addRefund.remark"
  406. style="width: 300px"
  407. :rows="2"
  408. maxlength="100"
  409. show-word-limit
  410. type="textarea"
  411. />
  412. </el-form-item>
  413. <el-form-item prop="adminName" label="提交人">
  414. <el-input
  415. style="width: 300px"
  416. :value="adminData.adminName"
  417. disabled
  418. placeholder="提交人姓名"
  419. />
  420. </el-form-item>
  421. <el-button type="success" @click="cancel()" style="margin-left: 280px">重置</el-button>
  422. <el-button type="primary" @click="addBefore"> 提交 </el-button>
  423. </el-form>
  424. <!-- 客户信息栏 -->
  425. <el-card v-if=user.jwcode style="width: 850px; float: right" class="customer-info">
  426. <el-form
  427. :model="user"
  428. label-width="auto"
  429. style="max-width: 1000px"
  430. label-position="left"
  431. >
  432. <el-text size="large" style="margin-left: 20px">客户信息</el-text>
  433. <el-row style="margin-top: 20px">
  434. <el-col :span="10">
  435. <el-form-item label="姓名:">
  436. <p>{{ user.name }}</p>
  437. </el-form-item>
  438. </el-col>
  439. <el-col :span="14">
  440. <el-form-item label="历史金币总数">
  441. <!-- 检查 user.totalRechargeGold 是否为有效的数字 -->
  442. <p v-if="!isNaN(Number(user.historySumGold))">
  443. {{ Number(user.historySumGold) }}
  444. </p>
  445. <!-- 如果不是有效的数字显示默认值 -->
  446. <p v-else></p>
  447. </el-form-item>
  448. </el-col>
  449. <el-col :span="10">
  450. <el-form-item label="精网号">
  451. <p>{{ user.jwcode }}</p>
  452. </el-form-item>
  453. </el-col>
  454. <el-col :span="14">
  455. <el-form-item label="当前金币总数" style="width: 500px">
  456. <span
  457. style="color: #2fa1ff; margin-right: 5px"
  458. v-if="user.nowSumGold !== undefined"
  459. >{{
  460. (user.nowSumGold)
  461. }}</span
  462. >
  463. <span
  464. style="display: inline; white-space: nowrap; color: #b1b1b1"
  465. v-if="user.nowPermanentGold !== undefined"
  466. >(永久金币:{{ user.nowPermanentGold }};免费金币:{{
  467. (user.nowFreeGold)
  468. }};任务金币:{{ user.nowTaskGold}})</span
  469. >
  470. </el-form-item>
  471. </el-col>
  472. <el-col :span="10">
  473. <el-form-item label="首次充值日期">
  474. <p v-if="user.firstRecharge">
  475. {{ moment(user.firstRecharge).format('YYYY-MM-DD HH:mm:ss') }}
  476. </p>
  477. </el-form-item>
  478. </el-col>
  479. <el-col :span="14">
  480. <el-form-item label="充值次数">
  481. <p style="color: #2fa1ff">{{ user.rechargeNum }}</p>
  482. </el-form-item>
  483. </el-col>
  484. <!-- <el-col :span="10">
  485. <el-form-item label="负责客服">
  486. <p>{{ adminData.name }}</p>
  487. </el-form-item>
  488. </el-col> -->
  489. <el-col :span="10">
  490. <el-form-item label="消费次数">
  491. <p style="color: #2fa1ff">{{ user.consumeNum }}</p>
  492. </el-form-item>
  493. </el-col>
  494. <el-col :span="10">
  495. <el-form-item label="所属门店">
  496. <p>{{ user.market }}</p>
  497. </el-form-item>
  498. </el-col>
  499. <el-col :span="14">
  500. </el-col>
  501. </el-row>
  502. </el-form>
  503. </el-card>
  504. </div>
  505. </template>
  506. <style scoped>
  507. p {
  508. margin: 0px;
  509. }
  510. .el-form-item {
  511. margin-left: 50px;
  512. }
  513. /* 上传图片的格式 */
  514. .avatar-uploader .avatar {
  515. width: 50px;
  516. height: 50px;
  517. display: block;
  518. }
  519. </style>
  520. <style>
  521. .avatar-uploader .el-upload {
  522. border: 1px dashed var(--el-border-color);
  523. border-radius: 6px;
  524. cursor: pointer;
  525. position: relative;
  526. overflow: hidden;
  527. transition: var(--el-transition-duration-fast);
  528. }
  529. .avatar-uploader .el-upload:hover {
  530. border-color: var(--el-color-primary);
  531. }
  532. .el-icon.avatar-uploader-icon {
  533. font-size: 28px;
  534. color: #8c939d;
  535. width: 50px;
  536. height: 50px;
  537. text-align: center;
  538. }
  539. .form-style {
  540. margin-top: 50px;
  541. max-width: 50%;
  542. float: left;
  543. }
  544. .form-style2 {
  545. max-width: 60%;
  546. }
  547. p {
  548. font-size: 13px;
  549. transform: scale(1);
  550. }
  551. </style>