Compare commits

...

10 Commits

  1. 82
      package-lock.json
  2. 1
      package.json
  3. 29
      src/App.vue
  4. 12
      src/assets/SvgIcons/mutiple-language.svg
  5. 3
      src/components/dialogs/ConfirmDialog.vue
  6. 114
      src/components/dialogs/LanguageSwitch.vue
  7. 28
      src/components/locales/index.js
  8. 104
      src/components/locales/lang/en.js
  9. 34
      src/components/locales/lang/th.js
  10. 388
      src/components/locales/lang/zh-CN.js
  11. 14
      src/main.ts
  12. 7
      src/router/index.js
  13. 12
      src/util/request.js
  14. 4
      src/utils/menuTreePermission.js
  15. 4
      src/utils/menuUtils.js
  16. 2
      src/views/activityManage/activity.vue
  17. 121
      src/views/audit/bean/beanAudit.vue
  18. 5
      src/views/audit/gold/audit.vue
  19. 164
      src/views/audit/gold/rechargeAudit.vue
  20. 183
      src/views/audit/gold/refundAudit.vue
  21. 161
      src/views/consume/gold/addCoinConsume.vue
  22. 5
      src/views/consume/gold/coinConsume.vue
  23. 127
      src/views/consume/gold/coinConsumeDetail.vue
  24. 18
      src/views/home.vue
  25. 535
      src/views/language/languageTranslate.vue
  26. 197
      src/views/recharge/gold/addCoinRecharge.vue
  27. 7
      src/views/recharge/gold/coinRecharge.vue
  28. 121
      src/views/recharge/gold/coinRechargeDetail.vue
  29. 138
      src/views/refund/gold/addCoinRefund.vue
  30. 5
      src/views/refund/gold/coinRefund.vue
  31. 114
      src/views/refund/gold/coinRefundDetail.vue

82
package-lock.json

@ -27,6 +27,7 @@
"pinia": "^3.0.2",
"pinyin-match": "^1.2.8",
"vue": "^3.5.12",
"vue-i18n": "^9.14.5",
"vue-icons-plus": "^0.1.7",
"vue-json-excel": "^0.3.0",
"vue-router": "^4.5.0",
@ -115,6 +116,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz",
"integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
"dev": true,
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.26.2",
@ -2018,6 +2020,7 @@
"version": "6.7.2",
"resolved": "https://registry.npmmirror.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
"integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
"peer": true,
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.7.2"
},
@ -2045,6 +2048,50 @@
"vue": ">= 3.0.0 < 4"
}
},
"node_modules/@intlify/core-base": {
"version": "9.14.5",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.5.tgz",
"integrity": "sha512-5ah5FqZG4pOoHjkvs8mjtv+gPKYU0zCISaYNjBNNqYiaITxW8ZtVih3GS/oTOqN8d9/mDLyrjD46GBApNxmlsA==",
"license": "MIT",
"dependencies": {
"@intlify/message-compiler": "9.14.5",
"@intlify/shared": "9.14.5"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/message-compiler": {
"version": "9.14.5",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.14.5.tgz",
"integrity": "sha512-IHzgEu61/YIpQV5Pc3aRWScDcnFKWvQA9kigcINcCBXN8mbW+vk9SK+lDxA6STzKQsVJxUPg9ACC52pKKo3SVQ==",
"license": "MIT",
"dependencies": {
"@intlify/shared": "9.14.5",
"source-map-js": "^1.0.2"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/shared": {
"version": "9.14.5",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.5.tgz",
"integrity": "sha512-9gB+E53BYuAEMhbCAxVgG38EZrk59sxBtv3jSizNL2hEWlgjBjAw1AwpLHtNaeda12pe6W20OGEa0TwuMSRbyQ==",
"license": "MIT",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.8",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
@ -2746,6 +2793,7 @@
"resolved": "https://mirrors.huaweicloud.com/repository/npm/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/lodash": "*"
}
@ -2756,6 +2804,7 @@
"integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~6.20.0"
}
@ -3292,6 +3341,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001688",
"electron-to-chromium": "^1.5.73",
@ -4196,13 +4246,15 @@
"version": "4.17.21",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/lodash-unified": {
"version": "1.0.3",
@ -4672,6 +4724,7 @@
"integrity": "sha512-wc2cBWqJgkU3Iz5oztRkQbfVkbxoz5EhnCGOrnJvnLnQ7O0WhQUYyv18qQI79O8L7DdHrrlJNeCHd4VGpnaXKQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/estree": "1.0.6"
},
@ -4749,6 +4802,7 @@
"resolved": "https://registry.npmmirror.com/sass/-/sass-1.86.3.tgz",
"integrity": "sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw==",
"dev": true,
"peer": true,
"dependencies": {
"chokidar": "^4.0.0",
"immutable": "^5.0.2",
@ -4895,6 +4949,7 @@
"integrity": "sha512-GWANVlPM/ZfYzuPHjq0nxT+EbOEDDN3Jwhwdg1D8TU8oSkktp8w64Uq4auuGLxFSoNTRDncTq2hQHX1Ld9KHkA==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
@ -4948,6 +5003,7 @@
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"devOptional": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@ -5040,6 +5096,7 @@
"integrity": "sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.24.2",
"postcss": "^8.5.1",
@ -5131,6 +5188,7 @@
"resolved": "https://mirrors.huaweicloud.com/repository/npm/vue/-/vue-3.5.13.tgz",
"integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.13",
"@vue/compiler-sfc": "3.5.13",
@ -5147,6 +5205,26 @@
}
}
},
"node_modules/vue-i18n": {
"version": "9.14.5",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.14.5.tgz",
"integrity": "sha512-0jQ9Em3ymWngyiIkj0+c/k7WgaPO+TNzjKSNq9BvBQaKJECqn9cd9fL4tkDhB5G1QBskGl9YxxbDAhgbFtpe2g==",
"license": "MIT",
"dependencies": {
"@intlify/core-base": "9.14.5",
"@intlify/shared": "9.14.5",
"@vue/devtools-api": "^6.5.0"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
},
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/vue-icons-plus": {
"version": "0.1.7",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/vue-icons-plus/-/vue-icons-plus-0.1.7.tgz",

1
package.json

@ -31,6 +31,7 @@
"pinia": "^3.0.2",
"pinyin-match": "^1.2.8",
"vue": "^3.5.12",
"vue-i18n": "^9.14.5",
"vue-icons-plus": "^0.1.7",
"vue-json-excel": "^0.3.0",
"vue-router": "^4.5.0",

29
src/App.vue

@ -1,9 +1,26 @@
<script setup>
</script>
<template>
<router-view></router-view>
<el-config-provider :locale="elLocale">
<router-view />
</el-config-provider>
</template>
<style scoped>
</style>
<script setup>
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
// Element Plus
import zhCnLocale from 'element-plus/dist/locale/zh-cn.mjs'
import enLocale from 'element-plus/dist/locale/en.mjs'
import thLocale from 'element-plus/dist/locale/th.mjs'
const { locale } = useI18n()
// i18n Element Plus
const elLocale = computed(() => {
switch (locale.value) {
case 'zh-CN': return zhCnLocale
case 'en': return enLocale
case 'th': return thLocale
default: return zhCnLocale
}
})
</script>

12
src/assets/SvgIcons/mutiple-language.svg

@ -0,0 +1,12 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 31 31" class="design-iconfont">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.0085 0.38608C11.9389 0.0559933 15.4797 -0.285745 20.5862 0.38608C25.6927 1.0579 28.9411 3.89977 30.0237 7.3258C31.1063 10.7518 31.0277 17.4517 30.6289 20.8033C30.3013 24.8149 27.9662 29.5636 22.3821 30.3908C16.7979 31.2181 9.93529 30.9975 7.18245 30.0172C4.42961 29.0369 0.783904 26.9498 0.307218 21.1038C-0.169468 15.2577 -0.484463 7.41159 2.49025 4.23018C4.55287 1.77953 8.07806 0.716166 10.0085 0.38608Z" fill="#C0F2FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.61719 23.264V7.64694C3.61719 6.23685 4.76029 5.09375 6.17038 5.09375H10.9232C12.4762 5.09375 14.0013 5.49747 15.3494 6.26363L15.5321 6.37035C16.6369 5.54169 17.9808 5.09375 19.3619 5.09375H24.8938C26.3039 5.09375 27.447 6.23685 27.447 7.64694V23.264C27.447 24.6741 26.3039 25.8172 24.8938 25.8172H19.3619C18.0383 25.8172 16.749 26.2285 15.6714 26.9922L15.5321 27.0938C14.1399 26.2584 12.5468 25.8172 10.9232 25.8172H6.17038C4.76029 25.8172 3.61719 24.6741 3.61719 23.264Z" fill="url(#zc4k4a1w8__paint0_linear_1264_34725)"/>
<path d="M21.7535 8.27734H9.12647C8.28947 8.27734 7.60547 8.96134 7.60547 9.79834V19.0593C7.60547 19.8963 8.28947 20.5803 9.12647 20.5803H13.0685L15.0305 22.5423C15.1475 22.6593 15.2915 22.7133 15.4445 22.7133C15.5975 22.7133 15.7415 22.6593 15.8585 22.5423L17.8205 20.5803H21.7625C22.5995 20.5803 23.2835 19.8963 23.2835 19.0593V9.79834C23.2745 8.96134 22.5995 8.27734 21.7535 8.27734ZM22.1045 19.0593C22.1045 19.2483 21.9515 19.4103 21.7535 19.4103H17.6945C17.5145 19.3743 17.3165 19.4283 17.1725 19.5723L15.4445 21.3003L13.7165 19.5723C13.5725 19.4283 13.3745 19.3743 13.1945 19.4103H9.12647C8.93747 19.4103 8.77547 19.2573 8.77547 19.0593V9.79834C8.77547 9.60934 8.92847 9.44734 9.12647 9.44734H21.7535C21.9515 9.44734 22.1045 9.60034 22.1045 9.79834V19.0593Z" fill="#fff"/>
<path d="M10.8119 10.9941C10.5149 10.9941 10.2719 11.2281 10.2539 11.5251V17.1051C10.2539 17.4111 10.5059 17.6631 10.8119 17.6631C11.1179 17.6631 11.3699 17.4111 11.3699 17.1051V11.5251C11.3519 11.2281 11.1089 10.9941 10.8119 10.9941ZM15.5009 13.1001C15.3389 12.9741 15.1319 12.8841 14.8979 12.8391C14.6639 12.7851 14.3939 12.7671 14.0969 12.7671C13.8449 12.7671 13.6199 12.7941 13.4309 12.8391C13.2419 12.8841 13.0709 12.9471 12.9269 13.0191C12.7829 13.0911 12.6569 13.1811 12.5579 13.2711C12.4769 13.3521 12.4049 13.4421 12.3509 13.5231C12.2699 13.6221 12.2159 13.7481 12.2159 13.8831C12.2159 14.1891 12.4679 14.4411 12.7739 14.4411C13.0439 14.4411 13.2689 14.2521 13.3229 14.0001L13.3319 13.9911C13.3769 13.9461 13.4309 13.9011 13.4939 13.8651C13.5659 13.8291 13.6469 13.7931 13.7369 13.7751C13.8359 13.7481 13.9439 13.7391 14.0789 13.7391C14.2139 13.7391 14.3399 13.7481 14.4479 13.7751C14.5469 13.7931 14.6279 13.8291 14.6909 13.8741C14.7539 13.9191 14.7989 13.9731 14.8349 14.0451C14.8709 14.1171 14.8889 14.2251 14.8889 14.3421V14.4231L14.0339 14.5041C13.7819 14.5311 13.5479 14.5671 13.3409 14.6301C13.1249 14.6931 12.9269 14.7741 12.7649 14.8911C12.6029 15.0081 12.4679 15.1701 12.3779 15.3591C12.2879 15.5481 12.2339 15.7821 12.2339 16.0521C12.2339 16.2591 12.2699 16.4481 12.3329 16.6281C12.3959 16.7991 12.4949 16.9611 12.6209 17.0871C12.7469 17.2131 12.8999 17.3211 13.0799 17.3841C13.2599 17.4561 13.4669 17.4921 13.7009 17.4921C13.9799 17.4921 14.2409 17.4291 14.4839 17.3121C14.6369 17.2311 14.7899 17.1411 14.9339 17.0331V17.2041C14.9339 17.5011 15.1769 17.7441 15.4739 17.7441C15.7709 17.7441 16.0139 17.5011 16.0139 17.2041V14.3601C16.0139 14.0631 15.9689 13.8111 15.8879 13.6041C15.7979 13.3971 15.6719 13.2261 15.5009 13.1001ZM14.8889 16.0431C14.8169 16.0971 14.7449 16.1601 14.6729 16.2051C14.5829 16.2681 14.4929 16.3221 14.4119 16.3671C14.3219 16.4121 14.2409 16.4481 14.1599 16.4751C14.0789 16.5021 14.0069 16.5111 13.9349 16.5111C13.7459 16.5111 13.6109 16.4751 13.5119 16.4031C13.4219 16.3401 13.3859 16.2051 13.3859 16.0251C13.3859 15.9171 13.4039 15.8181 13.4489 15.7461C13.4939 15.6741 13.5479 15.6111 13.6289 15.5571C13.7189 15.5031 13.8269 15.4581 13.9529 15.4311C14.0879 15.3951 14.2499 15.3771 14.4299 15.3591L14.8979 15.3141V16.0431H14.8889ZM20.4959 13.2081C20.3879 13.0641 20.2439 12.9471 20.0639 12.8751C19.8929 12.8031 19.6769 12.7671 19.4249 12.7671C19.2809 12.7671 19.1369 12.7851 18.9929 12.8301C18.8489 12.8751 18.7139 12.9291 18.5789 12.9921C18.4439 13.0641 18.3269 13.1451 18.2009 13.2351L18.0929 13.3161V13.2171V13.2981C18.0929 12.9921 17.8409 12.7491 17.5349 12.7491C17.2289 12.7491 16.9769 12.9921 16.9769 13.2981V13.2171V17.1951C16.9769 17.5011 17.2289 17.7531 17.5349 17.7531C17.8409 17.7531 18.0929 17.5011 18.0929 17.1951V14.3871C18.1739 14.3151 18.2549 14.2521 18.3449 14.1801C18.4439 14.1081 18.5429 14.0361 18.6419 13.9821C18.7409 13.9281 18.8309 13.8831 18.9299 13.8471C19.0199 13.8201 19.1009 13.8021 19.1729 13.8021C19.2899 13.8021 19.3799 13.8201 19.4429 13.8471C19.4969 13.8741 19.5419 13.9191 19.5779 13.9911C19.6139 14.0721 19.6409 14.1711 19.6499 14.3061C19.6589 14.4501 19.6679 14.6211 19.6679 14.8281V17.1951C19.6679 17.5011 19.9199 17.7531 20.2259 17.7531C20.5319 17.7531 20.7839 17.5011 20.7839 17.1951V14.4141C20.7839 14.1621 20.7659 13.9371 20.7209 13.7391C20.6849 13.5321 20.6039 13.3521 20.4959 13.2081Z" fill="#fff"/>
<defs>
<linearGradient id="zc4k4a1w8__paint0_linear_1264_34725" x1="39.3619" y1="16.0938" x2="19.665" y2="-7.37491" gradientUnits="userSpaceOnUse">
<stop stop-color="#2FB7FC"/>
<stop offset="1" stop-color="#82DEFF"/>
</linearGradient>
</defs>
</svg>

3
src/components/dialogs/ConfirmDialog.vue

@ -14,7 +14,7 @@
@close="handleClose">
<div class="confirm-content">
将要{{ message }}
{{ $t('common.will') }}{{ message }}
<br>
</div>
@ -34,6 +34,7 @@
<script setup>
import { ref, watch } from 'vue'
import BackgroundSvg from '@/assets/SvgIcons/promptBackground.svg'
import { useI18n } from 'vue-i18n'
//
const props = defineProps({

114
src/components/dialogs/LanguageSwitch.vue

@ -0,0 +1,114 @@
<template>
<el-dialog
v-model="dialogVisible"
title="语言切换"
width="300px"
:close-on-click-modal="false"
append-to-body
class="lang-switch-dialog"
>
<el-form label-width="80px">
<el-form-item label="切换语言">
<el-select
v-model="tempLang"
placeholder="请选择语言"
style="width: 100%"
>
<el-option
v-for="item in langOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="handleConfirm"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useI18n } from 'vue-i18n'
// === Element Plus ===
import {
ElDialog,
ElForm,
ElFormItem,
ElInput,
ElSelect,
ElOption,
ElButton,
ElMessage
} from 'element-plus'
const { locale } = useI18n()
//
const dialogVisible = ref(false)
//
const currentLang = computed(() => locale.value)
//
const tempLang = ref('')
//
const langOptions = [
{ label: '中文(简体)', value: 'zh-CN' },
{ label: '中文(繁體)', value: 'zh-TW' },
{ label: '英语', value: 'en' },
{ label: 'ภาษาไทย', value: 'th' },
{ label: 'Tiếng Việt', value: 'vi' }
]
//
const getLangLabel = (langCode) => {
const find = langOptions.find(item => item.value === langCode)
return find ? find.label : langCode
}
//
const open = () => {
tempLang.value = currentLang.value
dialogVisible.value = true
}
//
const handleConfirm = () => {
locale.value = tempLang.value
localStorage.setItem('lang', tempLang.value)
ElMessage.success(`语言已切换为:${getLangLabel(tempLang.value)}`)
dialogVisible.value = false
//
setTimeout(() => {
window.location.reload()
}, 500)
}
defineExpose({
open
})
</script>
<style scoped>
.dialog-footer {
display: flex;
justify-content: center;
gap: 20px;
}
/* :deep(.el-dialog__body) {
height: 220px !important;
overflow-y: auto !important;
} */
</style>

28
src/components/locales/index.js

@ -0,0 +1,28 @@
import { createI18n } from 'vue-i18n'
// 引入你的本地语言包
import zhCN from './lang/zh-CN'
import en from './lang/en'
import th from './lang/th' // 泰文
// 组合语言包
const messages = {
'zh-CN': zhCN,
'en': en,
'th': th
}
// 获取浏览器默认语言或缓存语言
const getLocale = () => {
// 优先读取缓存,没有则读取浏览器语言,默认 zh-CN
return localStorage.getItem('lang') || 'zh-CN'
}
const i18n = createI18n({
legacy: false, // Vue 3 组合式 API 必须设置为 false
globalInjection: true, // 全局注入 $t 函数
locale: getLocale(), // 初始化语言
messages // 语言包数据
})
export default i18n

104
src/components/locales/lang/en.js

@ -0,0 +1,104 @@
export default {
// Common Group
common: {
// Filters
jwcode: 'jwcode',
jwcodePlaceholder: 'Please enter jwcode',
activityName: 'Activity Name',
activityNamePlaceholder: 'Please enter activity name',
goodsName: 'Goods Name',
goodsNamePlaceholder: 'Please enter goods name',
payModel: 'Payment Method',
payModelPlaceholder: 'Please select payment method',
refundType: 'Refund Type',
refundTypePlaceholder: 'Please select refund type',
market: 'Market',
marketPlaceholder: 'Please select market',
submitTime: 'Submit Time',
auditTime: 'Audit Time',
startTime: 'Start Time',
to: 'To',
endTime: 'End Time',
// Button Group
search: 'Search',
reset: 'Reset',
edit: 'Edit',
pass: 'Pass',
reject: 'Reject',
cancel: 'Cancel',
confirm: 'Confirm',
// Currency Types
SGD: 'SGD',
goldCoin: '', // Gold Coin label intentionally empty
// 对话框标题
will: 'Will',
},
// Audit Group
audit: {
// Audit Common
refundTypeOptions: {
'商品退款': 'Product Refund',
'金币退款': 'Gold Refund',
},
waitAudit: 'Pending Audit',
passed: 'Approved',
rejected: 'Rejected',
permanentGold: 'Permanent',
freeGold: 'Free',
taskGold: 'Task',
// Audit Common - List Fields
id: 'ID',
name: 'Name',
jwcode: 'JW Code',
market: 'Market',
activityName: 'Activity Name',
currencyName: 'Currency Name',
rechargeAmount: 'Recharge Amount',
note: 'Note',
payModel: 'Payment Method',
paymentVoucher: 'Payment Voucher',
submitter: 'Submitter',
auditor: 'Auditor',
rejectReason: 'Reject Reason',
rejectReasonPlaceholder: 'Please enter reject reason',
paymentTime: 'Payment Time',
submitTime: 'Submit Time',
auditTime: 'Audit Time',
operation: 'Operation',
// Supplement Fields for Refund Audit
orderCode: 'Order Number',
refundType: 'Refund Type',
refundModel: 'Refund Method',
allRefund: 'Full Refund',
partialRefund: 'Partial Refund',
refundGoods: 'Refund Goods',
// Gold Recharge Audit ------------------------
rechargeAudit: 'Recharge Audit',
rechargeSGD: 'Recharge SGD',
totalGold: 'Total Gold',
// 添加支付方式翻译
payMethods: {
bankTransfer: 'Bank Transfer',
cash: 'Cash',
check: 'Check',
card: 'Card Payment',
grabpay: 'Grabpay',
nets: 'Nets',
paypal: 'PayPal',
stripe: 'Stripe - Link Payment',
ipay88: 'Ipay88 - Link Payment',
paymentAsia: 'PaymentAsia - Link Payment',
other: 'Other'
},
// Gold Refund Audit --------------------------
refundAudit: 'Refund Audit',
refundTotalGold: 'Total Refund',
},
}

34
src/components/locales/lang/th.js

@ -0,0 +1,34 @@
export default {
common: {
jwcode: 'jwcode',
jwcodePlaceholder: 'กรุณาใส่ jwcode',
activityName: 'ชื่อกิจกรรม',
activityNamePlaceholder: 'กรุณาใส่ชื่อกิจกรรม',
goodsName: 'ชื่อสินค้า',
goodsNamePlaceholder: 'กรุณาใส่ชื่อสินค้า',
refundType: 'ประเภทการคืนเงิน',
refundTypePlaceholder: 'กรุณาเลือกประเภทการคืนเงิน',
payModel: 'วิธีการชำระเงิน',
payModelPlaceholder: 'กรุณาเลือกวิธีการชำระเงิน',
market: 'ตลาด',
marketPlaceholder: 'กรุณาเลือกตลาด',
submitTime: 'เวลาส่ง',
auditTime: 'เวลาตรวจสอบ',
startTime: 'เวลาเริ่มต้น',
to: 'ถึง',
endTime: 'เวลาสิ้นสุด',
search: 'ค้นหา',
reset: 'รีเซ็ต',
},
audit: {
rechargeAudit: 'การตรวจสอบการเติมเงิน',
refundAudit: 'การตรวจสอบการคืนเงิน',
refundTypeOptions: {
'商品退款': 'คืนเงินสินค้า',
'金币退款': 'คืนเงินทอง',
},
waitAudit: 'รอตรวจสอบ',
passed: 'อนุมัติ',
rejected: 'ปฏิเสธ',
}
}

388
src/components/locales/lang/zh-CN.js

@ -0,0 +1,388 @@
import { UploadFilled } from "@element-plus/icons-vue";
export default {
// 通用组 (筛选,按钮,币种计量)
common: {
// 筛选
jwcode: '精网号',
jwcodePlaceholder: '请输入精网号',
activityName: '活动名称',
activityNamePlaceholder: '请输入活动名称',
goodsName: '商品名称',
goodsNamePlaceholder: '请输入商品名称',
payModel: '支付方式',
payModelPlaceholder: '请选择支付方式',
refundType: '退款类型',
refundTypePlaceholder: '请选择退款类型',
market: '所属地区',
marketPlaceholder: '请选择所属地区',
consumePlatform: '消耗平台',
consumePlatformPlaceholder: '请选择消耗平台',
rechargePlatform: '充值平台',
rechargePlatformPlaceholder: '请选择充值平台',
consumeTime: '消耗时间',
rechargeTime: '充值时间',
refundTime: '退款时间',
submitTime: '提交时间',
auditTime: '审核时间',
startTime: '起始时间',
to: '至',
endTime: '结束时间',
// 按钮组
search: '查询',
exportExcel: '导出Excel',
viewExportList: '查看导出列表',
reset: '重置',
edit: '编辑',
pass: '通过',
reject: '驳回',
cancel: '取消',
confirm: '确认',
submit: '提交',
confrimRecharge: '确认充值',
// 按钮组-日期
today: '今',
yesterday: '昨',
last7Days: '近7天',
// 币种计量单位类型
rechargeSGD: '充值新币',
consumeSGD: '消耗新币',
refundGoldCoin: '退款金币总数',
totalGoldCoin: '总金币数',
permanentGold: '永久金币',
freeGold: '免费金币',
taskGold: '任务金币',
SGD: '新币',
goldCoin: '金币',
: '条',
: '个',
goldBean: '金豆',
// 对话框标题
will: '将要',
},
// 提示信息组
elmessage: {
// 通用
addSuccess: '添加成功',
searchSuccess: '查询成功',
requestFailed: '请求失败',
jwcodeError: '精网号错误',
addFailedUnknown: '添加失败,未知错误',
addFailed: '添加失败,请检查网络连接或联系管理员',
queryFailed: '查询失败,请检查网络连接或精网号是否正确',
refundTypeError: '退款类型数据格式错误,请联系管理员',
confirmRefund: '确认退款?',
// 校验精网号,充值等输入
checkInputContent: '请检查输入内容',
permanentAndFreeNoZero: '永久金币和免费金币不能同时为0',
checkRate: '请选择币种名称',
checkMoney: '请输入充值金额',
checkJwcode: '请输入精网号',
checkGoodsName: '请选择商品',
checkUserInfo: '请先查询用户信息',
checkActivity: '请输入活动名称',
checkPermanentGold: '请输入永久金币数',
checkFreeGold: '请输入免费金币数',
checkTaskGold: '请输入任务金币数',
checkNumber: '请输入有效的数字',
checkPayModel: '请选择付款方式',
checkPayTime: '请选择交款时间',
checkQueryParams: '请检查查询参数',
checkRefundType: '请选择退款类型',
checkRefundGoods: '请选择退款商品',
checkOrderNo: '请输入订单号',
// 校验提示(error)
noEmptyJwcode: '精网号不能为空',
noEmptySumGold: '消耗金币总数不能为空',
noUser: '用户不存在',
noOrder: '未查询到相关订单',
noTotalGoldZero: '总金币数不能为0',
noNegativeNumber: '不能输入负数',
limitDigitJwcode: '精网号只能包含数字',
limitNoSpecialChar: '不能包含特殊符号或负数',
limitNegativeNumber: '消耗金币总数不能为负数',
limitExceeded: '消耗金币总数超过可用金币总和',
limitSix: '整数位数不能超过6位',
limitTwoDecimal: '小数位数不能超过两位',
limitZero: '输入金额不能小于0',
limitPositiveNumber: '请输入大于0的正数(可包含最多两位小数)',
limitJwcodeNine: '精网号必须为数字且不超过九位',
limitBalance: '所填金额大于该类金币余额',
// 图片上传
onlyUploadJPGPNG: '只能上传 JPG/PNG 图片!',
limitImageSize: '图片大小不能超过 1MB!',
uploadSuccess: '上传成功',
UploadFailed: '上传失败',
// 审核
noPermission: '暂无权限',
checkJwcodeFormat: '请检查精网号格式',
rejectReasonPlaceholder: '请输入驳回理由',
rejectSuccess: '驳回成功',
rejectFailed: '驳回失败',
operationFailed: '操作失败',
approveSuccess: '审核通过成功',
approveFailed: '审核通过失败',
activityFormatError: '活动数据格式错误,请联系管理员',
rechargeFormatError: '充值方式格式错误,请联系管理员',
getRechargeError: '获取充值方式失败,请稍后重试',
// 导出相关
exportSuccess: '导出成功',
exportFailed: '导出失败,请稍后重试',
getExportListError: '获取导出列表失败,请稍后重试',
exportingInProgress: '文件还在导出中,请稍后再试',
// 导出状态标签
pendingExecution: '待执行',
executing: '执行中',
executed: '执行完成',
errorExecution: '执行出错',
unknownStatus: '未知状态',
},
// 通用列表字段组
common_list: {
id: '序号',
name: '姓名',
jwcode: '精网号',
market: '所属地区',
orderNo: '订单号',
goodsName: '商品名称',
refundType: '退款类型',
refundModel: '退款方式',
refundModelAll: '全部退款',
refundModelPart: '部分退款',
refundGoldCoin: '退款金币总数',
activity: '活动名称',
rateName: '货币名称',
rechargeAmount: '充值金额',
permanentGold: '永久金币',
freeGold: '免费金币',
taskGold: '任务金币',
rechargePlatform: '充值平台',
consumePlatform: '消耗平台',
consumeTotalGold: '消耗金币总数',
payModel: '支付方式',
remark: '备注',
orderStatus: '订单状态',
submitter: '提交人',
rechargeTime: '充值时间',
consumeTime: '消耗时间',
refundTime: '退款时间',
},
// 通用导出字段组
common_export: {
exportList: '导出列表',
fileName: '文件名称',
status: '状态',
createTime: '创建时间',
operation: '操作',
download: '下载',
close: '关闭',
},
// 新增表单字段组
common_add: {
jwcode: '精网号',
activity: '活动名称',
activityPlaceholder: '请输入活动名称',
permanentGold: '永久金币',
freeGold: '免费金币',
taskGold: '任务金币',
rechargeAmount: '充值金额',
currencyName: '货币名称',
goodsName: '商品名称',
goodsNamePlaceholder: '请选择商品',
payModel: '收款方式',
refundType: '退款类型',
refundTypePlaceholder: '请选择退款类型',
orderNo: '订单号',
orderNoPlaceholder: '请选择订单号',
refundModel: '退款方式',
refundModelAll: '全部退款',
refundModelPart: '部分退款',
refundGoldCoin: '退款金币总数',
payModelPlaceholder: '请选择收款方式',
consumeTotalGold: '消耗金币总数',
totalGold: '金币总数',
paymentTime: '交款时间',
paymentVoucher: '交款凭证',
paymentVoucherPlaceholder: '仅支持.jpg .png格式,文件≤1MB',
remark: '备注',
// 确认表单
operationConfirm: '操作确认',
userInfo: '用户信息',
prompt: '重复充值风险提示',
similarRechargeRecords: '检测到该用户近期有相似充值记录',
rechargePermanentGold: '充值永久金币',
buy: '购买',
operator: '操作人',
continueOperation: '是否继续操作',
},
// 新增表单客户信息字段组
common_add_user: {
customerInfo: '客户信息',
name: '姓名',
currentGoldCoinTotal: '当前金币总数',
permanentGold: '永久金币',
freeGold: '免费金币',
taskGold: '任务金币',
jwcode: '精网号',
consumptionTimes: '消费次数',
onlyStatisticsDataAfter20250101: '仅统计2025-01-01后的数据',
store: '所属门店',
},
// 审核组
audit: { // 按照项目文件名分配
// 审核通用 ----------------------------------------------------------
refundTypeOptions: {
'商品退款': '商品退款',
'金币退款': '金币退款',
},
waitAudit: '待审核',
passed: '已通过',
rejected: '已驳回',
permanentGold: '永久金币',
freeGold: '免费金币',
taskGold: '任务金币',
// 审核通用-充值审核列表字段
id: '序号',
name: '姓名',
jwcode: '精网号',
market: '所属地区',
activityName: '活动名称',
currencyName: '货币名称',
rechargeAmount: '充值金额',
note: '备注',
payModel: '支付方式',
paymentVoucher: '支付凭证',
submitter: '提交人',
auditor: '审核人',
rejectReason: '驳回理由',
rejectReasonPlaceholder: '请输入驳回理由',
paymentTime: '交款时间',
submitTime: '提交时间',
auditTime: '审核时间',
operation: '操作',
// 审核通用-充值审核列表字段-补充退款审核列表字段
orderCode: '订单号',
refundType: '退款类型',
refundModel: '退款方式',
allRefund: '全部退款',
partialRefund: '部分退款',
refundGoods: '退款商品',
// 审核通用-金豆审核列表字段补充
permanentBean: '付费金豆',
freeBean: '免费金豆',
// 金币充值审核 --------------------------------
rechargeAudit: '充值审核',
rechargeSGD: '充值新币',
totalGold: '总金币数',
// 添加支付方式
payMethods: {
bankTransfer: '银行转账',
cash: '现金',
check: '支票',
card: '刷卡',
grabpay: 'Grabpay',
nets: 'Nets',
paypal: 'PayPal',
stripe: 'Stripe-链接收款',
ipay88: 'Ipay88-链接收款',
paymentAsia: 'PaymentAsia-链接收款',
other: '其他'
},
// 金币退款审核 --------------------------------
refundAudit: '退款审核',
refundTotalGold: '退款总金币数',
// 金豆审核 ------------------------------------
totalNum: '总条数',
totalBean: '总金豆数',
permanentBean: '付费金豆',
freeBean: '免费金豆',
// 对话框的标题
rejectRecord: '驳回该记录!',
passRecord: '通过该记录!',
},
// 充值组
recharge: {
// 金币充值明细 ---------------------------------
coinRechargeDetail: '金币充值明细',
// 订单状态
normal: '正常',
refunded: '已退款',
unknown: '未知状态',
// 金币新增充值 ---------------------------------
addCoinRecharge: '新增充值',
// 支付方式
// 添加支付方式
payMethods: {
bankTransfer: '银行转账',
cash: '现金',
check: '支票',
card: '刷卡',
grabpay: 'Grabpay',
nets: 'Nets',
paypal: 'PayPal',
stripe: 'Stripe-链接收款',
ipay88: 'Ipay88-链接收款',
paymentAsia: 'PaymentAsia-链接收款',
other: '其他'
},
},
// 消耗组
consume: {
// 金币消耗明细 ---------------------------------
coinConsumeDetail: '金币消耗明细',
// 订单状态
normal: '正常',
refunded: '已退款',
unknown: '未知状态',
// 消费平台选项
consumePlatforms: {
goldSystem: '金币系统',
HomilyChart: 'HomilyChart',
HomilyLink: 'HomilyLink',
ERP: 'ERP',
other: '其他',
initGold: '初始化金币',
},
// 新增消耗
addCoinConsume: '新增消耗',
},
//退款组
refund: {
// 金币退款明细 ---------------------------------
coinRefundDetail: '金币退款明细',
// 订单状态
normal: '正常',
refunded: '已退款',
unknown: '未知状态',
// 退款方式选项
refundMethods: {
allRefund: '全部退款',
partialRefund: '部分退款',
},
// 新增退款
refundTypeOptions: {
'商品退款': '商品退款',
'金币退款': '金币退款',
},
addCoinRefund: '新增退款',
// 新增退款的用户表单
id: '序号',
type: '类型',
recharge: '充值',
consume: '消费',
productName: '商品名称',
orderCode: '订单号',
permanentGold: '永久金币',
freeGold: '免费金币',
taskGold: '任务金币',
isRefund: '允许退款',
no: '否',
yes: '是',
},
}

14
src/main.ts

@ -18,6 +18,8 @@ import request from "@/util/request";
import "./global.css";
import '@/assets/css/btn.css';
import {useMessageStore} from "@/store";
import i18n from './components/locales'
const app = createApp(App)
@ -40,6 +42,7 @@ app.use(ElementPlus, {
.use(VxeUI)
.use(VxeUITable)
.use(pinia)
.use(i18n)
.mount('#app')
// 在 app 挂载之后再使用 store
@ -47,3 +50,14 @@ const adminStore = useAdminStore()
const messageStore = useMessageStore()
adminStore.initFromLocalStorage()
messageStore.initFromLocalStorage()
// 初始化语言设置
const initLanguage = () => {
const lang = localStorage.getItem('lang')
if (!lang) {
// 如果没有设置语言,默认使用中文
localStorage.setItem('lang', 'zh-CN')
}
}
initLanguage()

7
src/router/index.js

@ -419,6 +419,13 @@ const routes = [
component: () => import("../views/activityManage/activity.vue"),
meta: {permissionId: 119}
},
// 多语言配置
{
path: 'language',
name: "language",
component: () => import("../views/language/languageTranslate.vue"),
meta: {permissionId: 146}
},
// 没有权限
{
path: '/noPermission',

12
src/util/request.js

@ -2,7 +2,7 @@ import axios from 'axios'
// 创建axios实例
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE,//.env.development
timeout: 1000000,
timeout: 20000, // 20秒超时
headers: {
'Content-Type': 'application/json'
},
@ -26,15 +26,13 @@ export const uploadFile = (file) => {
service.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
// 请求体里面为什么放token?
// if (config.data) {
// config.data.token = token;
// } else {
// config.data = { token };
// }
config.headers.token = `${token}`
}
// 统一使用 'lang' 作为键名
const lang = localStorage.getItem('lang') || 'zh-CN'
config.headers.lang = lang
return config
}, error => {
return Promise.reject(error)
})

4
src/utils/menuTreePermission.js

@ -166,7 +166,9 @@ export const permissionMapping = {
view_personal_information: 142, // 查看个人信息
change_password: 143, // 修改密码
logout_system: 144, // 退出登录
message_push: 145 // 消息推送
message_push: 145, // 消息推送
mutiple_language: 146, // 多语言配置
}
// 递归查找菜单中是否存在目标id

4
src/utils/menuUtils.js

@ -48,6 +48,8 @@ export const getRoutePath = (menu) => {
'金币管理': '/goldManage',
'现金管理': '/moneyManage',
'活动管理': '/activityManage',
'频道管理': '/channelManage',
'多语言配置': '/language',
'金币审核': '/audit',
'金豆审核': '/beanAudit',
@ -92,7 +94,7 @@ export const getRoutePath = (menu) => {
'执行明细': '/moneyManage/executor',
'频道管理': '/channelManage',
'打赏管理': '/channelManage/reward',
'铁粉管理': '/channelManage/fans',
'小黄车管理': '/channelManage/cart',

2
src/views/activityManage/activity.vue

@ -33,7 +33,7 @@
<el-card class="card2">
<div class="add-item">
<el-button type="success" @click="showAdd = true" style="margin-top: 1vh;">新增活动</el-button>
<el-button type="success" @click="showAdd = true">新增活动</el-button>
</div>
<div>
<el-table :data="tableData" style="width: 82vw;height:70vh;" :row-style="{ height: '50px' }">

121
src/views/audit/bean/beanAudit.vue

@ -3,13 +3,13 @@
<el-col style="margin-bottom: 1vh">
<div class="select">
<div class="selectRow">
<el-text class="text" size="large">精网号</el-text>
<el-input class="selectContent" v-model="searchForm.jwcode" placeholder="请输入精网号"
<el-text class="text" size="large">{{ $t('common.jwcode') }}</el-text>
<el-input class="selectContent" v-model="searchForm.jwcode" :placeholder="t('common.jwcodePlaceholder')"
style="width: 12vw;margin-right:1vw" clearable />
</div>
<div class="selectRow">
<el-text class="text" size="large">所属地区</el-text>
<el-cascader v-model="selectedMarkets" :options="marketOptions" placeholder="请选择所属地区" clearable
<el-text class="text" size="large">{{ $t('common.market') }}</el-text>
<el-cascader v-model="selectedMarkets" :options="marketOptions" :placeholder="$t('common.marketPlaceholder')" clearable
style="width: 12vw" @change="handleMarketChange" />
</div>
</div>
@ -17,18 +17,18 @@
<el-col>
<div class="select">
<div class="selectRow" style="width: 36vw;">
<el-text class="text" size="large" v-show="checkTab === 'pending'">提交时间</el-text>
<el-text class="text" size="large" v-show="checkTab === 'reject' || checkTab === 'pass'">审核时间</el-text>
<el-date-picker v-model="dateRange" type="datetimerange" range-separator="" start-placeholder="开始时间"
end-placeholder="结束时间" class="selectContent" style="width: 25vw;margin-right:1vw"
<el-text class="text" size="large" v-show="checkTab === 'pending'">{{ $t('common.submitTime') }}</el-text>
<el-text class="text" size="large" v-show="checkTab === 'reject' || checkTab === 'pass'">{{ $t('common.auditTime') }}</el-text>
<el-date-picker v-model="dateRange" type="datetimerange" range-separator="" :start-placeholder="$t('common.startTime')"
:end-placeholder="$t('common.endTime')" class="selectContent" style="width: 25vw;margin-right:1vw"
@change="handleDatePickerChange" :default-time="defaultTime" />
<!-- <el-button @click="getToday()" :type="activeTimeRange === 'today' ? 'primary' : ''"></el-button>-->
<!-- <el-button @click="getYesterday()" :type="activeTimeRange === 'yesterday' ? 'primary' : ''"></el-button>-->
<!-- <el-button @click="get7Days()" :type="activeTimeRange === '7days' ? 'primary' : ''">近7天</el-button>-->
</div>
<div class="selectRow" style="justify-content: flex-start;">
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button type="success" @click="resetSearch">重置</el-button>
<el-button type="primary" @click="handleSearch">{{ t('common.search') }}</el-button>
<el-button type="success" @click="resetSearch">{{ t('common.reset') }}</el-button>
</div>
</div>
@ -40,62 +40,62 @@
<div class="custom-button-group">
<el-button v-if="hasbeanWait && hasbeanWaitShow" :type="checkTab === 'pending' ? 'primary' : 'default'"
class="custom-tab-button" @click="adminWait">
待审核
{{ $t('audit.waitAudit') }}
</el-button>
<el-button v-if="hasbeanThrough" :type="checkTab === 'pass' ? 'primary' : 'default'" class="custom-tab-button"
@click="adminPass">
已通过
{{ $t('audit.passed') }}
</el-button>
<el-button v-if="hasbeanReject" :type="checkTab === 'reject' ? 'primary' : 'default'" class="custom-tab-button"
@click="adminReject">
已驳回
{{ $t('audit.rejected') }}
</el-button>
</div>
<div class="goldStatistics">
总条数{{ format3(stats.num) }}&nbsp;&nbsp;&nbsp;&nbsp;
总金豆数{{ format3(stats.beanNum) }}金豆&nbsp;&nbsp;&nbsp;&nbsp;
付费金豆{{ format3(stats.permanentBean) }}金豆&nbsp;&nbsp;&nbsp;&nbsp;
免费金豆{{ format3(stats.freeBean) }}金豆
{{ $t('audit.totalNum') }}{{ format3(stats.num) }}{{ $t('common.') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('audit.totalBean') }}{{ format3(stats.beanNum) }}{{ $t('common.goldBean') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('audit.permanentBean') }}{{ format3(stats.permanentBean) }}{{ $t('common.goldBean') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('audit.freeBean') }}{{ format3(stats.freeBean) }}{{ $t('common.goldBean') }}
</div>
<el-table :data="tableData" height="65vh" @sort-change="handleSortChange" :row-style="{ height: '50px' }">
<el-table-column type="index" label="序号" width="80">
<el-table-column type="index" :label="$t('audit.id')" width="80">
<template #default="scope">
{{ scope.$index + 1 + (pagination.pageNum - 1) * pagination.pageSize }}
</template>
</el-table-column>
<el-table-column prop="name" label="姓名" width="120" show-overflow-tooltip />
<el-table-column prop="jwcode" label="精网号" width="120" />
<el-table-column prop="market" label="所属地区" width="120" />
<el-table-column prop="permanentBean" label="付费金豆" width="120" sortable="custom" />
<el-table-column prop="freeBean" label="免费金豆" width="120" sortable="custom" />
<el-table-column prop="remark" label="备注" width="150" show-overflow-tooltip />
<el-table-column prop="submitName" label="提交人" width="120" />
<el-table-column v-if="checkTab === 'reject'" prop="reason" label="驳回理由" width="120" show-overflow-tooltip />
<el-table-column v-if="checkTab !== 'pending'" prop="auditName" label="审核人" width="120" />
<el-table-column prop="createTime" label="提交时间" width="180" sortable="custom">
<el-table-column prop="name" :label="$t('audit.name')" width="120" show-overflow-tooltip />
<el-table-column prop="jwcode" :label="$t('audit.jwcode')" width="120" />
<el-table-column prop="market" :label="$t('audit.market')" width="120" />
<el-table-column prop="permanentBean" :label="$t('audit.permanentBean')" width="120" sortable="custom" />
<el-table-column prop="freeBean" :label="$t('audit.freeBean')" width="120" sortable="custom" />
<el-table-column prop="remark" :label="$t('audit.note')" width="150" show-overflow-tooltip />
<el-table-column prop="submitName" :label="$t('audit.submitter')" width="120" />
<el-table-column v-if="checkTab === 'reject'" prop="reason" :label="$t('audit.rejectReason')" width="120" show-overflow-tooltip />
<el-table-column v-if="checkTab !== 'pending'" prop="auditName" :label="$t('audit.auditor')" width="120" />
<el-table-column prop="createTime" :label="$t('audit.submitTime')" width="180" sortable="custom">
<template #default="{ row }">
{{ moment(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column v-if="checkTab !== 'pending'" prop="auditTime" label="审核时间" width="240" sortable="custom">
<el-table-column v-if="checkTab !== 'pending'" prop="auditTime" :label="$t('audit.auditTime')" width="240" sortable="custom">
<template #default="{ row }">
{{ row.auditTime ? moment(row.auditTime).format('YYYY-MM-DD HH:mm:ss') : '--' }}
</template>
</el-table-column>
<el-table-column v-if="checkTab === 'pending' && (hasbeanWaitThough || hasbeanWaitReject)" fixed="right"
prop="operation" label="操作" width="200px">
prop="operation" :label="$t('audit.operation')" width="200px">
<template #default="scope">
<div class="operation">
<el-link :underline="false" class="pass-btn" v-if="hasbeanWaitThough" :disabled="clicked || cancelClicked"
type="primary" @click="showApproveDialog(scope.row)">
通过
{{ $t('common.pass') }}
</el-link>
<el-link :underline="false" class="reject-btn" v-if="hasbeanWaitReject" :disabled="clicked || cancelClicked"
type="primary" @click="showRejectDialog(scope.row)">
驳回
{{ $t('common.reject') }}
</el-link>
</div>
</template>
@ -109,23 +109,23 @@
</el-card>
<!-- 驳回理由对话框 -->
<el-dialog v-model="rejectReasonDialogVisible" title="驳回理由" width="500px">
<el-dialog v-model="rejectReasonDialogVisible" :title="$t('audit.rejectReason')" width="500px" @close="handleRejectReasonCancel">
<el-form>
<el-form-item label="驳回理由" required>
<el-input v-model="reason" type="textarea" :rows="4" placeholder="请输入驳回理由" maxlength="200" show-word-limit />
<el-form-item :label="$t('audit.rejectReason')" required>
<el-input v-model="reason" type="textarea" :rows="4" :placeholder="$t('audit.rejectReasonPlaceholder')" maxlength="200" show-word-limit />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="rejectReasonDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleReject()">确定</el-button>
<el-button @click="handleRejectReasonCancel">{{ $t('common.cancel') }}</el-button>
<el-button :disabled="cancelClicked" type="primary" @click="handleReject">{{ $t('common.confirm') }}</el-button>
</span>
</template>
</el-dialog>
<ConfirmDialog
v-model="rejectDialogVisible"
message="驳回该记录!"
:message="$t('audit.rejectRecord')"
@confirm="showRejectReasonInput"
@cancel="handleRejectCancel"
@close="handleRejectClose"
@ -133,7 +133,7 @@
<ConfirmDialog
v-model="approveDialogVisible"
message="通过该记录!"
:message="$t('audit.passRecord')"
@confirm="handleApproveConfirm"
@cancel="handleApproveCancel"
@close="handleApproveClose"
@ -151,6 +151,9 @@ import { storeToRefs } from "pinia";
import _ from 'lodash'
import { permissionMapping, hasMenuPermission } from "@/utils/menuTreePermission.js"
import ConfirmDialog from '@/components/dialogs/ConfirmDialog.vue';
// i18n
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const defaultTime = [
new Date(2000, 1, 1, 0, 0, 0),
@ -263,7 +266,7 @@ const handleSearch = async function () {
if (searchForm.value.jwcode) {
const numRef = /^\d{1,9}$/;
if (!numRef.test(searchForm.value.jwcode)) {
ElMessage.error('请检查精网号格式')
ElMessage.error(t('elmessage.checkJwcodeFormat'))
return
}
}
@ -272,7 +275,7 @@ const handleSearch = async function () {
}
const get = async function () {
if (!hasbeanWaitShow) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
try {
@ -320,7 +323,7 @@ const get = async function () {
}
const getStats = async () => {
if (!hasbeanWaitShow) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
try {
@ -353,7 +356,7 @@ const getStats = async () => {
//
const showApproveDialog = (row) => {
if (!hasbeanWaitThough) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
passRow.value.id = row.id
@ -365,7 +368,7 @@ const showApproveDialog = (row) => {
// handleApprove
const handleApproveConfirm = async function() {// rowrow
if (!hasbeanWaitThough) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
clicked.value = true
@ -375,14 +378,14 @@ const handleApproveConfirm = async function() {// 不要再传row了!哪有row
auditName: adminData.value.adminName
}
await API({ url: '/beanAudit/status1', data: params })
ElMessage.success('审核通过成功')
ElMessage.success(t('elmessage.approveSuccess'))
approveDialogVisible.value = false
await get()
clicked.value = false
await getStats()
} catch (error) {
console.error('审核通过失败', error)
ElMessage.error('操作失败')
console.error(t('elmessage.approveFailed'), error)
ElMessage.error(t('elmessage.operationFailed'))
}
}
//
@ -396,12 +399,12 @@ const handleApproveClose = () => {
//
const handleReject = async () => {
if (!hasbeanWaitReject) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
cancelClicked.value = true
if (!reason.value.trim()) {
ElMessage.warning('请输入驳回理由')
ElMessage.warning(t('elmessage.rejectReasonPlaceholder'))
return
}
try {
@ -411,14 +414,14 @@ const handleReject = async () => {
reason: reason.value
}
await API({ url: '/beanAudit/status2', data: params })
ElMessage.success('驳回成功')
ElMessage.success(t('elmessage.rejectSuccess'))
rejectReasonDialogVisible.value = false
await get()
cancelClicked.value = false
await getStats()
} catch (error) {
console.error('驳回失败', error)
ElMessage.error('操作失败')
console.error(t('elmessage.rejectFailed'), error)
ElMessage.error(t('elmessage.operationFailed'))
}
}
//
@ -434,6 +437,12 @@ const handleRejectCancel = () => {
const handleRejectClose = () => {
rejectDialogVisible.value = false
}
//
const handleRejectReasonCancel = () => {
rejectReasonDialogVisible.value = false
cancelClicked.value = false //
reason.value = '' //
}
// handleApproveConfirm
const throttledHandleApprove = _.throttle(handleApproveConfirm, 5000, {
trailing: false
@ -441,7 +450,7 @@ const throttledHandleApprove = _.throttle(handleApproveConfirm, 5000, {
//
const showRejectDialog = (row) => {
if (!hasbeanWaitReject) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
rejectRow.value.id = row.id
@ -505,19 +514,19 @@ const handleClick = async function (tab) {
checkTab.value = tab.props.name
if (tab.props.name === 'pending') {
if (!hasbeanWait) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
adminWait()
} else if (tab.props.name === 'pass') {
if (!hasbeanThrough) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
adminPass()
} else if (tab.props.name === 'reject') {
if (!hasbeanReject) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
adminReject()

5
src/views/audit/gold/audit.vue

@ -8,7 +8,7 @@
@click="navigateTo('rechargeAudit')"
v-if="hasRecharge"
>
充值审核
{{ $t('audit.rechargeAudit') }}
</el-button>
<el-button
class="no-active-btn"
@ -16,7 +16,7 @@
@click="navigateTo('refundAudit')"
v-if="hasRefund"
>
退款审核
{{ $t('audit.refundAudit') }}
</el-button>
</el-button-group>
</div>
@ -31,6 +31,7 @@ import { storeToRefs } from 'pinia';
import { useAdminStore } from '@/store/index.js';
import { hasMenuPermission, permissionMapping } from "@/utils/menuTreePermission.js";
import { ElMessage } from 'element-plus';
import { useI18n } from 'vue-i18n';
const router = useRouter();
const route = useRoute();

164
src/views/audit/gold/rechargeAudit.vue

@ -3,24 +3,24 @@
<el-col style="margin-bottom: 1vh">
<div class="select">
<div class="selectRow">
<el-text class="text" size="large">精网号</el-text>
<el-input class="selectContent" v-model="rechargeAudit.jwcode" placeholder="请输入精网号" clearable />
<el-text class="text" size="large">{{ $t('common.jwcode') }}</el-text>
<el-input class="selectContent" v-model="rechargeAudit.jwcode" :placeholder="$t('common.jwcodePlaceholder')" clearable />
</div>
<div class="selectRow">
<el-text class="text" size="large">活动名称</el-text>
<el-select class="selectContent" v-model="rechargeAudit.activity" placeholder="请选择活动名称" clearable>
<el-text class="text" size="large">{{ $t('common.activityName') }}</el-text>
<el-select class="selectContent" v-model="rechargeAudit.activity" :placeholder="$t('common.activityNamePlaceholder')" clearable>
<el-option v-for="item in activity" :key="item" :label="item" :value="item" />
</el-select>
</div>
<div class="selectRow">
<el-text class="text" size="large">支付方式</el-text>
<el-select class="selectContent" v-model="rechargeAudit.payModel" placeholder="请选择支付方式" clearable>
<el-text class="text" size="large">{{ $t('common.payModel') }}</el-text>
<el-select class="selectContent" v-model="rechargeAudit.payModel" :placeholder="$t('common.payModelPlaceholder')" clearable>
<el-option v-for="item in payModel" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div class="selectRow">
<el-text class="text" size="large">所属地区</el-text>
<el-cascader class="selectContent" v-model="selectedMarketPath" :options="market" placeholder="请选择所属地区"
<el-text class="text" size="large">{{ $t('common.market') }}</el-text>
<el-cascader class="selectContent" v-model="selectedMarketPath" :options="market" :placeholder="$t('common.marketPlaceholder')"
clearable @change="handleMarketChange" />
</div>
</div>
@ -29,10 +29,10 @@
<div class="select">
<div class="selectRow" style="width: 36vw;">
<el-text class="text" size="large">
{{ activeName === 'wait' ? '提交时间:' : '审核时间:' }}
{{ activeName === 'wait' ? $t('common.submitTime') : $t('common.auditTime') }}
</el-text>
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" range-separator=""
start-placeholder="起始时间" end-placeholder="结束时间" style="margin-right:1vw;width:25vw"
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" :range-separator="$t('common.to')"
:start-placeholder="$t('common.startTime')" :end-placeholder="$t('common.endTime')" style="margin-right:1vw;width:25vw"
@change="handleDatePickerChange" :default-time="defaultTime" :disabled-date="disabledDate" />
<div v-if="false">
<el-button @click="getToday()" :type="activeTimeRange === 'today' ? 'primary' : ''"></el-button>
@ -42,8 +42,8 @@
</div>
<div class="selectRow" style="justify-content: flex-start;">
<el-button @click="handleSearch" type="primary">查询</el-button>
<el-button @click="resetSearch" type="success">重置</el-button>
<el-button @click="handleSearch" type="primary">{{ $t('common.search') }}</el-button>
<el-button @click="resetSearch" type="success">{{ $t('common.reset') }}</el-button>
</div>
</div>
</el-col>
@ -56,7 +56,7 @@
@click="handleButtonClick('wait')"
class="custom-tab-button"
>
待审核
{{ $t('audit.waitAudit') }}
</el-button>
<el-button
v-if="hasrechargeThrough"
@ -64,7 +64,7 @@
@click="handleButtonClick('pass')"
class="custom-tab-button"
>
已通过
{{ $t('audit.passed') }}
</el-button>
<el-button
v-if="hasrechargeReject"
@ -72,62 +72,62 @@
@click="handleButtonClick('reject')"
class="custom-tab-button"
>
已驳回
{{ $t('audit.rejected') }}
</el-button>
</div>
<div class="goldStatistics">
<!-- 总条数{{ format3(stats.totalNum) }}&nbsp;&nbsp;&nbsp;&nbsp;-->
充值新币{{ format3(stats.permanentGolds) }}新币&nbsp;&nbsp;&nbsp;&nbsp;
总金币数{{ format3((stats.permanentGolds + stats.freeGolds + stats.taskGolds).toFixed(2))
}}金币&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(stats.permanentGolds.toFixed(2)) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
免费金币{{ format3(stats.freeGolds.toFixed(2)) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('audit.rechargeSGD') }}{{ format3(stats.permanentGolds) }} {{ $t('common.SGD') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('audit.totalGold') }}{{ format3((stats.permanentGolds + stats.freeGolds + stats.taskGolds).toFixed(2))
}}{{ $t('common.goldCoin') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('audit.permanentGold') }}{{ format3(stats.permanentGolds.toFixed(2)) }}{{ $t('common.goldCoin') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('audit.freeGold') }}{{ format3(stats.freeGolds.toFixed(2)) }}{{ $t('common.goldCoin') }}&nbsp;&nbsp;&nbsp;&nbsp;
</div>
<el-table :data="tableData" style="width: 82vw;height:61vh" @sort-change="handleSortChange"
:row-style="{ height: '50px' }">
<el-table-column type="index" label="序号" width="100px" fixed="left">
<el-table-column type="index" :label="$t('audit.id')" width="100px" fixed="left">
<template #default="scope">
<span>{{ scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize }}</span>
</template>
</el-table-column>
<el-table-column fixed="left" prop="name" label="姓名" width="150px" show-overflow-tooltip />
<el-table-column fixed="left" prop="jwcode" label="精网号" width="110px" />
<el-table-column prop="market" label="所属地区" width="100px" />
<el-table-column prop="activity" label="活动名称" width="100px" show-overflow-tooltip />
<el-table-column prop="rateName" label="货币名称" width="110px" />
<el-table-column prop="money" label="充值金额" sortable="custom" width="110px">
<el-table-column fixed="left" prop="name" :label="$t('audit.name')" width="150px" show-overflow-tooltip />
<el-table-column fixed="left" prop="jwcode" :label="$t('audit.jwcode')" width="110px" />
<el-table-column prop="market" :label="$t('audit.market')" width="120px" />
<el-table-column prop="activity" :label="$t('audit.activityName')" width="100px" show-overflow-tooltip />
<el-table-column prop="rateName" :label="$t('audit.currencyName')" width="110px" />
<el-table-column prop="money" :label="$t('audit.rechargeAmount')" sortable="custom" width="110px">
<template #default="scope">{{ scope.row.money / 100 }}</template>
</el-table-column>
<el-table-column prop="permanentGold" label="永久金币" width="110px" sortable="custom">
<el-table-column prop="permanentGold" :label="$t('audit.permanentGold')" width="130px" sortable="custom">
<template #default="scope">{{ scope.row.permanentGold / 100 }}</template>
</el-table-column>
<el-table-column prop="freeGold" label="免费金币" sortable="custom" width="110px">
<el-table-column prop="freeGold" :label="$t('audit.freeGold')" sortable="custom" width="110px">
<template #default="scope">{{ (scope.row.freeGold) / 100 }}</template>
</el-table-column>
<el-table-column prop="remark" label="备注" width="180px" show-overflow-tooltip />
<el-table-column prop="payModel" label="支付方式" width="130px" />
<el-table-column prop="voucher" label="支付凭证" width="110px">
<el-table-column prop="remark" :label="$t('audit.note')" width="180px" show-overflow-tooltip />
<el-table-column prop="payModel" :label="$t('audit.payModel')" width="130px" />
<el-table-column prop="voucher" :label="$t('audit.paymentVoucher')" width="110px">
<template #default="scope">
<div v-if="scope.row.voucher"
style="display: flex; justify-content: center; align-items: center; cursor: pointer;"
@click="previewImage(scope.row.voucher)">
<img :src="scope.row.voucher" alt="支付凭证" style="width: auto; height: 40px;">
<img :src="scope.row.voucher" :alt="$t('audit.paymentVoucher')" style="width: auto; height: 40px;">
</div>
<div v-else style="display: flex; justify-content: center; align-items: center; height: 40px;">--</div>
</template>
</el-table-column>
<el-table-column prop="adminName" label="提交人" width="100px" />
<el-table-column prop="rejectReason" v-if="activeName === 'reject'" label="驳回理由" width="200px"
<el-table-column prop="adminName" :label="$t('audit.submitter')" width="100px" />
<el-table-column prop="rejectReason" v-if="activeName === 'reject'" :label="$t('audit.rejectReason')" width="200px"
show-overflow-tooltip />
<el-table-column v-if="activeName !== 'wait'" prop="auditName" label="审核人" width="100px" />
<el-table-column prop="payTime" sortable="custom" label="交款时间" width="200px">
<el-table-column v-if="activeName !== 'wait'" prop="auditName" :label="$t('audit.auditor')" width="100px" />
<el-table-column prop="payTime" sortable="custom" :label="$t('audit.paymentTime')" width="200px">
<template #default="scope">
{{ moment(scope.row.payTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column prop="createTime" sortable="custom" label="提交时间" width="200px">
<el-table-column prop="createTime" sortable="custom" :label="$t('audit.submitTime')" width="200px">
<template #default="scope">
<!-- {{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}-->
{{
@ -137,23 +137,23 @@
}}
</template>
</el-table-column>
<el-table-column v-if="activeName !== 'wait'" prop="auditTime" label="审核时间" width="200px">
<el-table-column v-if="activeName !== 'wait'" prop="auditTime" sortable="custom" :label="$t('audit.auditTime')" width="200px">
<template #default="scope">
{{ moment(scope.row.auditTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column v-if="activeName === 'wait'&&(hasrechargeWaitThough||hasrechargeWaitReject)&&hasrechargeWaitShow" fixed="right" prop="operation" label="操作" width="150px">
<el-table-column v-if="activeName === 'wait'&&(hasrechargeWaitThough||hasrechargeWaitReject)&&hasrechargeWaitShow" fixed="right" prop="operation" :label="$t('audit.operation')" width="150px">
<template #default="scope">
<div class="operation">
<el-link :underline="false" class="pass-btn" v-if="hasrechargeWaitThough"
:disabled="clicked || cancelClicked" type="primary"
@click="showApproveDialog(scope.row)">
通过
{{ $t('common.pass') }}
</el-link>
<el-link :underline="false" class="reject-btn" v-if="hasrechargeWaitReject"
:disabled="clicked || cancelClicked" type="primary"
@click="showRejectDialog(scope.row)">
驳回
{{ $t('common.reject') }}
</el-link>
</div>
</template>
@ -166,23 +166,23 @@
</div>
</el-card>
<el-dialog v-model="rejectReasonDialogVisible" title="驳回理由" width="500px">
<el-dialog v-model="rejectReasonDialogVisible" :title="$t('audit.rejectReason')" width="400px" @close="handleRejectReasonCancel">
<el-form>
<el-form-item label="驳回理由" required>
<el-input v-model="rejectReason" type="textarea" :rows="4" placeholder="请输入驳回理由" maxlength="200"
<el-form-item :label="$t('audit.rejectReason')" required>
<el-input v-model="rejectReason" type="textarea" :rows="4" :placeholder="$t('audit.rejectReason')" maxlength="200"
show-word-limit />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="rejectReasonDialogVisible = false">取消</el-button>
<el-button :disabled="cancelClicked" type="primary" @click="handleReject">确定</el-button>
<el-button @click="handleRejectReasonCancel">{{ $t('common.cancel') }}</el-button>
<el-button :disabled="cancelClicked" type="primary" @click="handleReject">{{ $t('common.confirm') }}</el-button>
</span>
</template>
</el-dialog>
<ConfirmDialog
v-model="rejectDialogVisible"
message="驳回该记录!"
:message="$t('audit.rejectRecord')"
@confirm="showRejectReasonInput"
@cancel="handleRejectCancel"
@close="handleRejectClose"
@ -191,7 +191,7 @@
<!-- 新增使用ConfirmDialog组件 -->
<ConfirmDialog
v-model="approveDialogVisible"
message="通过该记录!"
:message="$t('audit.passRecord')"
@confirm="handleApproveConfirm"
@cancel="handleApproveCancel"
@close="handleApproveClose"
@ -216,6 +216,9 @@ const { adminData, menuTree, flag } = storeToRefs(adminStore);
import { permissionMapping, hasMenuPermission } from "@/utils/menuTreePermission.js"
import dayjs from "dayjs";
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
// flag
watch(flag, (newFlag, oldFlag) => {
// flag
@ -301,47 +304,47 @@ const getObj = ref({
const payModel = [
{
value: '银行转账',
label: '银行转账'
label: t('audit.payMethods.bankTransfer')
},
{
value: '现金',
label: '现金'
label: t('audit.payMethods.cash')
},
{
value: '支票',
label: '支票'
label: t('audit.payMethods.check')
},
{
value: '刷卡',
label: '刷卡'
label: t('audit.payMethods.card')
},
{
value: 'Grabpay',
label: 'Grabpay'
label: t('audit.payMethods.grabpay')
},
{
value: 'Nets',
label: 'Nets'
label: t('audit.payMethods.nets')
},
{
value: 'PayPal',
label: 'PayPal'
label: t('audit.payMethods.paypal')
},
{
value: 'Stripe-链接收款',
label: 'Stripe-链接收款'
label: t('audit.payMethods.stripe')
},
{
value: 'Ipay88-链接收款',
label: 'Ipay88-链接收款'
label: t('audit.payMethods.ipay88')
},
{
value: 'PaymentAsia-链接收款',
label: 'PaymentAsia-链接收款'
label: t('audit.payMethods.paymentAsia')
},
{
value: '其他',
label: '其他'
label: t('audit.payMethods.other')
}
]
//
@ -354,13 +357,13 @@ const stats = ref({
})
//
const rules = reactive({
rejectReason: [{ required: true, message: '请输入驳回理由', trigger: 'blur' }]
rejectReason: [{ required: true, message: t('audit.rejectReasonPlaceholder'), trigger: 'blur' }]
})
//
const getRecharge = async function (val) {
if (!hasrechargeWaitShow) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
try {
@ -380,7 +383,7 @@ const getRecharge = async function (val) {
const numberRegex = /^\d{1,9}$/;
//
if (!numberRegex.test(rechargeAudit.value.jwcode)) {
ElMessage.error('请检查精网号格式')
ElMessage.error(t('common.checkJwcodeFormat'))
return
}
}
@ -538,7 +541,7 @@ const handleButtonClick = function (name) {
activeName.value = name
if (name === 'wait') {
if(!hasrechargeWait){
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
if(hasrechargeWaitShow){
@ -546,13 +549,13 @@ const handleButtonClick = function (name) {
}
} else if (name === 'pass') {
if(!hasrechargeThrough){
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
adminPass()
} else if (name === 'reject') {
if(!hasrechargeReject){
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
adminReject()
@ -610,7 +613,7 @@ const clicked = ref(false);
//
const showApproveDialog = (row) => {
if(!hasrechargeWaitThough){
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
currentRecord.value = row
@ -628,14 +631,14 @@ const handleApproveConfirm = async () => {
rejectReason: ''
}
await request({ url: '/audit/audit', data: params })
ElMessage.success('审核通过成功')
ElMessage.success(t('elmessage.approveSuccess'))
approveDialogVisible.value = false
await getRecharge()
clicked.value = false
await getStats()
} catch (error) {
console.error('审核通过失败', error)
ElMessage.error('操作失败')
console.error(t('elmessage.approveFailed'), error)
ElMessage.error(t('elmessage.operationFailed'))
clicked.value = false
}
}
@ -675,7 +678,7 @@ const handleApproveClose = () => {
// }
const showRejectDialog = (row) => {
if(!hasrechargeWaitReject){
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
currentRecord.value = row
@ -688,13 +691,13 @@ const cancelClicked = ref(false)
const handleReject = async () => {
// showRejectDialog
if(!hasrechargeWaitReject){
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
cancelClicked.value = true
if (!rejectReason.value.trim()) {
ElMessage.warning('请输入驳回理由')
ElMessage.warning(t('elmessage.rejectReasonPlaceholder'))
return
}
try {
@ -706,14 +709,14 @@ const handleReject = async () => {
}
await request({ url: '/audit/audit', data: params })
ElMessage.success('驳回操作成功')
ElMessage.success(t('elmessage.rejectSuccess'))
rejectReasonDialogVisible.value = false
await getRecharge()
cancelClicked.value = false
await getStats()
} catch (error) {
console.error('驳回操作失败', error)
ElMessage.error('操作失败')
console.error(t('elmessage.rejectFailed'), error)
ElMessage.error(t('elmessage.operationFailed'))
}
}
//
@ -729,6 +732,13 @@ const handleRejectCancel = () => {
const handleRejectClose = () => {
rejectDialogVisible.value = false
}
// /
const handleRejectReasonCancel = () => {
rejectReasonDialogVisible.value = false
cancelClicked.value = false //
rejectReason.value = '' //
}
//
const handleSortChange = (column) => {
console.log('排序字段:', column.prop)

183
src/views/audit/gold/refundAudit.vue

@ -3,26 +3,29 @@
<el-col style="margin-bottom: 1vh">
<div class="select">
<div class="selectRow">
<el-text class="text" size="large">精网号</el-text>
<el-input class="selectContent" v-model="searchForm.jwcode" placeholder="请输入精网号" clearable />
<el-text class="text" size="large">{{ $t('common.jwcode') }}</el-text>
<el-input class="selectContent" v-model="searchForm.jwcode" :placeholder="$t('common.jwcodePlaceholder')"
clearable />
</div>
<div class="selectRow">
<el-text class="text" size="large">商品名称</el-text>
<el-select class="selectContent" v-model="searchForm.goodsName" placeholder="请输入商品名称" clearable>
<el-text class="text" size="large">{{ $t('common.goodsName') }}</el-text>
<el-select class="selectContent" v-model="searchForm.goodsName"
:placeholder="$t('common.goodsNamePlaceholder')" clearable>
<el-option v-for="item in refundGoodsOptions" :key="item" :label="item" :value="item"></el-option>
</el-select>
</div>
<div class="selectRow">
<el-text class="text" size="large">退款类型</el-text>
<el-select class="selectContent" v-model="searchForm.refundType" placeholder="请选择退款类型" clearable>
<el-option label="商品退款" value="商品退款" />
<el-option label="金币退款" value="金币退款" />
<el-text class="text" size="large">{{ $t('common.refundType') }}</el-text>
<el-select class="selectContent" v-model="searchForm.refundType"
:placeholder="$t('common.refundTypePlaceholder')" clearable>
<el-option :label="$t('audit.refundTypeOptions.商品退款')" value="商品退款" />
<el-option :label="$t('audit.refundTypeOptions.金币退款')" value="金币退款" />
</el-select>
</div>
<div class="selectRow">
<el-text class="text" size="large">所属地区</el-text>
<el-text class="text" size="large">{{ $t('common.market') }}</el-text>
<el-cascader class="selectContent" style="width: 12vw;" v-model="selectedMarketPath" :options="market"
placeholder="请选择所属地区" clearable @change="handleMarketChange" />
:placeholder="$t('common.marketPlaceholder')" clearable @change="handleMarketChange" />
</div>
</div>
</el-col>
@ -30,11 +33,12 @@
<div class="select">
<div class="selectRow" style="width: 36vw;">
<el-text class="text" size="large">
{{ activeName === 'wait' ? '提交时间:' : '审核时间:' }}
{{ activeName === 'wait' ? $t('common.submitTime') : $t('common.auditTime') }}
</el-text>
<el-date-picker class="selectContent" v-model="dateRange" type="datetimerange" range-separator=""
start-placeholder="起始时间" end-placeholder="结束时间" style="margin-right:1vw;width:25vw"
@change="handleDatePickerChange" :default-time="defaultTime" :disabled-date="disabledDate" />
<el-date-picker class="selectContent" v-model="dateRange" type="datetimerange"
:range-separator="$t('common.to')" :start-placeholder="$t('common.startTime')"
:end-placeholder="$t('common.endTime')" style="margin-right:1vw;width:25vw" @change="handleDatePickerChange"
:default-time="defaultTime" :disabled-date="disabledDate" />
<div v-if="false">
<el-button @click="getToday()" :type="activeTimeRange === 'today' ? 'primary' : ''"></el-button>
<el-button @click="getYesterday()" :type="activeTimeRange === 'yesterday' ? 'primary' : ''"></el-button>
@ -42,8 +46,8 @@
</div>
</div>
<div class="selectRow" style="justify-content: flex-start;">
<el-button @click="handleSearch" type="primary">查询</el-button>
<el-button @click="resetSearch" type="success">重置</el-button>
<el-button @click="handleSearch" type="primary">{{ $t('common.search') }}</el-button>
<el-button @click="resetSearch" type="success">{{ $t('common.reset') }}</el-button>
</div>
</div>
</el-col>
@ -53,68 +57,70 @@
<div class="custom-button-group">
<el-button v-if="hasrefundWait && hasrefundWaitShow" :type="activeName === 'wait' ? 'primary' : 'default'"
@click="handleButtonClick('wait')" class="custom-tab-button">
待审核
{{ $t('audit.waitAudit') }}
</el-button>
<el-button v-if="hasrefundThrough" :type="activeName === 'pass' ? 'primary' : 'default'"
@click="handleButtonClick('pass')" class="custom-tab-button">
已通过
{{ $t('audit.passed') }}
</el-button>
<el-button v-if="hasrefundReject" :type="activeName === 'reject' ? 'primary' : 'default'"
@click="handleButtonClick('reject')" class="custom-tab-button">
已驳回
{{ $t('audit.rejected') }}
</el-button>
</div>
<div class="goldStatistics">
退款总金币数{{
{{ $t('audit.refundTotalGold') }}{{
format3((stats.permanentGolds + stats.freeGolds + stats.taskGolds).toFixed(2))
}}金币&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(stats.permanentGolds.toFixed(2)) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
免费金币{{ format3(stats.freeGolds.toFixed(2)) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
任务金币{{ format3(stats.taskGolds.toFixed(2)) }}金币
}}{{ $t('common.goldCoin') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('audit.permanentGold') }}{{ format3(stats.permanentGolds.toFixed(2)) }}{{ $t('common.goldCoin')
}}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('audit.freeGold') }}{{ format3(stats.freeGolds.toFixed(2)) }}{{ $t('common.goldCoin')
}}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('audit.taskGold') }}{{ format3(stats.taskGolds.toFixed(2)) }}{{ $t('common.goldCoin') }}
</div>
<el-table :data="tableData" style="height:61vh;width:82vw" @sort-change="handleSortChange"
:row-style="{ height: '50px' }">
<el-table-column fixed="left" type="index" label="序号" width="60" />
<el-table-column fixed="left" prop="name" label="姓名" width="120" show-overflow-tooltip />
<el-table-column fixed="left" prop="jwcode" label="精网号" width="120" />
<el-table-column prop="market" label="所属地区" width="120" />
<el-table-column prop="orderCode" label="订单号" width="260px" show-overflow-tooltip />
<el-table-column prop="refundType" label="退款类型" width="120" />
<el-table-column prop="refundModel" label="退款方式" width="120">
<el-table-column fixed="left" type="index" :label="$t('audit.id')" width="60" />
<el-table-column fixed="left" prop="name" :label="$t('audit.name')" width="120" show-overflow-tooltip />
<el-table-column fixed="left" prop="jwcode" :label="$t('audit.jwcode')" width="120" />
<el-table-column prop="market" :label="$t('audit.market')" width="120" />
<el-table-column prop="orderCode" :label="$t('audit.orderCode')" width="260px" show-overflow-tooltip />
<el-table-column prop="refundType" :label="$t('audit.refundType')" width="120" />
<el-table-column prop="refundModel" :label="$t('audit.refundModel')" width="120">
<template #default="{ row }">
{{ row.refundModel === 0 ? '全部退款' : '部分退款' }}
{{ row.refundModel === 0 ? $t('audit.allRefund') : $t('audit.partialRefund') }}
</template>
</el-table-column>
<el-table-column prop="goodsName" label="退款商品" width="120" show-overflow-tooltip />
<el-table-column prop="sumGold" label="退款金币总数" width="160" sortable="custom">
<el-table-column prop="goodsName" :label="$t('audit.refundGoods')" width="120" show-overflow-tooltip />
<el-table-column prop="sumGold" :label="$t('audit.refundTotalGold')" width="160" sortable="custom">
<template #default="{ row }">
{{ row.sumGold / 100 }}
</template>
</el-table-column>
<el-table-column prop="permanentGold" label="永久金币" width="120" sortable="custom">
<el-table-column prop="permanentGold" :label="$t('audit.permanentGold')" width="130" sortable="custom">
<template #default="{ row }">
{{ row.permanentGold / 100 }}
</template>
</el-table-column>
<el-table-column prop="freeGold" label="免费金币" width="120" sortable="custom">
<el-table-column prop="freeGold" :label="$t('audit.freeGold')" width="120" sortable="custom">
<template #default="{ row }">
{{ (row.freeJune + row.freeDecember) / 100 }}
</template>
</el-table-column>
<el-table-column prop="taskGold" label="任务金币" width="120" sortable="custom">
<el-table-column prop="taskGold" :label="$t('audit.taskGold')" width="120" sortable="custom">
<template #default="{ row }">
{{ row.taskGold / 100 }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" width="150" show-overflow-tooltip />
<el-table-column prop="adminName" label="提交人" width="120" />
<el-table-column v-if="checkTab === 'reject'" prop="rejectReason" label="驳回理由" width="150"
<el-table-column prop="remark" :label="$t('audit.note')" width="150" show-overflow-tooltip />
<el-table-column prop="adminName" :label="$t('audit.submitter')" width="120" />
<el-table-column v-if="checkTab === 'reject'" prop="rejectReason" :label="$t('audit.rejectReason')" width="150"
show-overflow-tooltip />
<el-table-column v-if="checkTab !== 'pending'" prop="auditName" label="审核人" width="120" />
<el-table-column prop="createTime" label="提交时间" width="180" sortable="custom">
<el-table-column v-if="checkTab !== 'pending'" prop="auditName" :label="$t('audit.auditor')" width="120" />
<el-table-column prop="createTime" :label="$t('audit.submitTime')" width="180" sortable="custom">
<template #default="{ row }">
{{
checkTab === 'pending'
@ -124,25 +130,23 @@
</template>
</el-table-column>
<el-table-column v-if="checkTab !== 'pending'" prop="auditTime" label="审核时间" width="180">
<el-table-column v-if="checkTab !== 'pending'" prop="auditTime" :label="$t('audit.auditTime')" width="180">
<template #default="{ row }">
{{ row.auditTime ? moment(row.auditTime).format('YYYY-MM-DD HH:mm:ss') : '--' }}
</template>
</el-table-column>
<el-table-column
v-if="checkTab === 'pending' && (hasrefundWaitThough || hasrefundWaitReject) && hasrefundWaitShow" fixed="right"
prop="operation" label="操作" width="150px">
prop="operation" :label="$t('audit.operation')" width="150px">
<template #default="scope">
<div class="operation">
<el-link :underline="false" class="pass-btn" v-if="hasrefundWaitThough"
:disabled="clicked || cancelClicked"type="primary"
@click="showApproveDialog(scope.row)">
通过
<el-link :underline="false" class="pass-btn" v-if="hasrefundWaitThough" :disabled="clicked || cancelClicked"
type="primary" @click="showApproveDialog(scope.row)">
{{ $t('common.pass') }}
</el-link>
<el-link :underline="false" class="reject-btn" v-if="hasrefundWaitReject"
:disabled="clicked || cancelClicked" type="primary"
@click="showRejectDialog(scope.row)">
驳回
:disabled="clicked || cancelClicked" type="primary" @click="showRejectDialog(scope.row)">
{{ $t('common.reject') }}
</el-link>
</div>
</template>
@ -153,38 +157,29 @@
@current-change="handleCurrentChange"></el-pagination>
</el-card>
<!-- 退款驳回理由输入框 -->
<el-dialog v-model="rejectReasonDialogVisible" title="驳回理由" width="500px">
<!-- 退款驳回理由输入框 -->
<el-dialog v-model="rejectReasonDialogVisible" :title="$t('audit.rejectReason')" width="500px"
@close="handleRejectReasonCancel">
<el-form>
<el-form-item label="驳回理由" required>
<el-input v-model="rejectReason" type="textarea" :rows="4" placeholder="请输入驳回理由" maxlength="200"
show-word-limit />
<el-form-item :label="$t('audit.rejectReason')" required>
<el-input v-model="rejectReason" type="textarea" :rows="4" :placeholder="$t('audit.rejectReasonPlaceholder')"
maxlength="200" show-word-limit />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="rejectReasonDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleReject">确定</el-button>
<el-button @click="handleRejectReasonCancel">{{ $t('common.cancel') }}</el-button>
<el-button :disabled="cancelClicked" type="primary" @click="handleReject">{{ $t('common.confirm') }}</el-button>
</span>
</template>
</el-dialog>
<ConfirmDialog
v-model="rejectDialogVisible"
message="驳回该记录!"
@confirm="showRejectReasonInput"
@cancel="handleRejectCancel"
@close="handleRejectClose"
/>
<ConfirmDialog v-model="rejectDialogVisible" :message="$t('audit.rejectRecord')" @confirm="showRejectReasonInput"
@cancel="handleRejectCancel" @close="handleRejectClose" />
<!-- 新增使用ConfirmDialog组件 -->
<ConfirmDialog
v-model="approveDialogVisible"
message="通过该记录!"
@confirm="handleApproveConfirm"
@cancel="handleApproveCancel"
@close="handleApproveClose"
/>
<ConfirmDialog v-model="approveDialogVisible" :message="$t('audit.passRecord')" @confirm="handleApproveConfirm"
@cancel="handleApproveCancel" @close="handleApproveClose" />
</template>
@ -198,11 +193,13 @@ import { storeToRefs } from "pinia";
import dayjs from "dayjs";
import { permissionMapping, hasMenuPermission } from "@/utils/menuTreePermission.js"
import ConfirmDialog from '@/components/dialogs/ConfirmDialog.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const adminStore = useAdminStore();
const { adminData, menuTree, flag } = storeToRefs(adminStore);
// flag
watch(flag, (newFlag, oldFlag) => {
watch(flag, (newFlag, oldFlag) => {
// flag
if (newFlag !== oldFlag) {
get()
@ -330,7 +327,7 @@ const getRefundGoods = async () => {
//
const get = async function (val) {
if (!hasrefundWaitShow) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
try {
@ -365,7 +362,7 @@ const get = async function (val) {
//
if (!numberRegex.test(searchForm.value.jwcode)) {
ElMessage.error('请检查精网号格式')
ElMessage.error(t('elmessage.checkJwcodeFormat'))
//
return
}
@ -381,8 +378,8 @@ const get = async function (val) {
const clicked = ref(false);
//
const showApproveDialog = (row) => {
if(!hasrefundWaitThough){
ElMessage.error('暂无权限')
if (!hasrefundWaitThough) {
ElMessage.error(t('elmessage.noPermission'))
return
}
currentRecord.value = row
@ -399,14 +396,14 @@ const handleApproveConfirm = async () => {
rejectReason: ''
}
await API({ url: '/audit/audit', data: params })
ElMessage.success('审核通过成功')
ElMessage.success(t('elmessage.approveSuccess'))
approveDialogVisible.value = false
await get()
clicked.value = false
await getStats()
} catch (error) {
console.error('审核通过失败', error)
ElMessage.error('操作失败')
console.error(t('elmessage.approveFailed'), error)
ElMessage.error(t('elmessage.operationFailed'))
}
}
//
@ -420,7 +417,7 @@ const handleApproveClose = () => {
//
const showRejectDialog = (row) => {
if (!hasrefundWaitReject) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
currentRecord.value = row
@ -432,13 +429,13 @@ const cancelClicked = ref(false)
//
const handleReject = async () => {
if (!hasrefundWaitReject) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
cancelClicked.value = true
if (!rejectReason.value.trim()) {
ElMessage.warning('请输入驳回理由')
ElMessage.warning(t('elmessage.rejectReasonPlaceholder'))
return
}
try {
@ -449,15 +446,15 @@ const handleReject = async () => {
rejectReason: rejectReason.value
}
await API({ url: '/audit/audit', data: params })
ElMessage.success('驳回成功')
ElMessage.success(t('elmessage.rejectSuccess'))
rejectReasonDialogVisible.value = false
await get()
cancelClicked.value = false
await getStats()
console.log('看看驳回参数', params)
} catch (error) {
console.error('驳回失败', error)
ElMessage.error('操作失败')
console.error(t('elmessage.rejectFailed'), error)
ElMessage.error(t('elmessage.operationFailed'))
}
}
//
@ -474,6 +471,12 @@ const handleRejectClose = () => {
rejectDialogVisible.value = false
}
//
const handleRejectReasonCancel = () => {
rejectReasonDialogVisible.value = false
cancelClicked.value = false //
rejectReason.value = '' //
}
const getStats = async () => {
if (!hasrefundWaitShow) {
return
@ -578,7 +581,7 @@ const handleButtonClick = function (name) {
activeName.value = name
if (name === 'wait') {
if (!hasrefundWait) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
if (hasrefundWaitShow) {
@ -586,13 +589,13 @@ const handleButtonClick = function (name) {
}
} else if (name === 'pass') {
if (!hasrefundThrough) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
adminPass()
} else if (name === 'reject') {
if (!hasrefundReject) {
ElMessage.error('暂无权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
adminReject()

161
src/views/consume/gold/addCoinConsume.vue

@ -1,13 +1,16 @@
<script setup>
import {onMounted, reactive, ref, watch} from "vue";
import {ElIcon, ElMessage} from "element-plus";
import { onMounted, reactive, ref, watch } from "vue";
import { ElIcon, ElMessage } 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 { useAdminStore } from "@/store/index.js";
import { storeToRefs } from "pinia";
import { WarnTriangleFilled } from "@element-plus/icons-vue";
import dayjs from "dayjs";
//
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const adminStore = useAdminStore();
const { adminData, menuTree } = storeToRefs(adminStore);
@ -22,7 +25,7 @@ const trimJwCode = () => {
if (!isNaN(numeric)) {
addConsume.value.jwcode = numeric
} else {
ElMessage.error("精网号格式不正确,请输入数字")
ElMessage.error(t('elmessage.limitDigitJwcode'))
}
}
}
@ -64,18 +67,18 @@ const addConsume = ref({
const Ref = ref(null)
const rules = reactive({
jwcode: [
{ required: true, message: "请输入精网号", trigger: "blur" },
{ required: true, message: t('elmessage.checkJwcode'), trigger: "blur" },
],
goodsName: [{ required: true, message: "请选择商品", trigger: "change" }],
goodsName: [{ required: true, message: t('elmessage.checkGoodsName'), trigger: "change" }],
sumGold: [
{ required: true, message: "消耗金币总数不能为空", trigger: "blur" },
{ required: true, message: t('elmessage.noEmptySumGold'), trigger: "blur" },
{
validator: (rule, value, callback) => {
// 00.10
const isValid = /^(0\.\d{1,2})|([1-9]\d*(\.\d{1,2})?)$/.test(value);
if (!isValid) {
callback(new Error("请输入大于0的正数(可包含最多两位小数)"));
callback(new Error(t('elmessage.limitPositiveNumber')));
} else {
callback();
}
@ -93,7 +96,7 @@ function validateInput() {
trimJwCode();
if (user.value.jwcode == null) {
ElMessage.warning("请先查询用户信息");
ElMessage.warning(t('elmessage.checkUserInfo'));
addConsume.value.sumGold = null;
user.value = {};
return false;
@ -115,7 +118,7 @@ function validateInput() {
}
//
if (sumGold < 0) {
ElMessage.warning("消耗金币总数不能为负数");
ElMessage.warning(t('elmessage.limitNegativeNumber'));
addConsume.value.sumGold = null;
return false;
}
@ -131,14 +134,14 @@ function validateInput() {
// 6
const truncatedInteger = integerPart.slice(0, 6);
addConsume.value.sumGold = parseFloat(truncatedInteger);
ElMessage.info('整数部分最多允许6位');
ElMessage.info(t('elmessage.limitSix'));
return; //
}
} else {
//
if (sumGoldStr.length > 6) {
addConsume.value.sumGold = parseFloat(sumGoldStr.slice(0, 6));
ElMessage.info('整数部分最多允许6位');
ElMessage.info(t('elmessage.limitSix'));
return;
}
}
@ -150,7 +153,7 @@ function validateInput() {
//
const truncatedValue = parseFloat(sumGoldStr.slice(0, sumGoldStr.indexOf('.') + 3));
addConsume.value.sumGold = truncatedValue;
ElMessage.info('最多允许输入两位小数');
ElMessage.info(t('elmessage.limitTwoDecimal'));
}
}
}
@ -159,7 +162,7 @@ function validateInput() {
//
const totalAvailableGold = (user.value.nowSumGold)
if (user.value.jwcode && sumGold > totalAvailableGold) {
ElMessage.error("消耗金币总数超过可用金币总和");
ElMessage.error(t('elmessage.limitExceeded'));
// sumGoldnull
addConsume.value.sumGold = null;
return false;
@ -255,7 +258,7 @@ const add = async function () {
} catch (error) {
console.error("请求失败", error);
ElMessage.error("添加失败,请检查网络连接或联系管理员");
ElMessage.error(t('elmessage.addFailed'));
}
};
@ -273,10 +276,10 @@ function handleResponse(result) {
expires:
1, path: '/'
});
ElMessage.success("添加成功");
ElMessage.success(t('elmessage.addSuccess'));
console.log("请求成功", result);
} else {
ElMessage.error(result.msg || "添加失败,未知错误");
ElMessage.error(result.msg || t('elmessage.addFailedUnknown'));
}
}
@ -385,7 +388,7 @@ const addBefore = () => {
if (!valid) {
ElMessage({
type: 'error',
message: '请检查输入内容'
message: t('elmessage.checkInputContent')
});
return;
}
@ -409,13 +412,13 @@ const getUser = async function (jwcode) {
try {
//
if (!jwcode) {
ElMessage.warning('精网号不能为空');
ElMessage.warning(t('elmessage.noEmptyJwcode'));
return;
}
//
if (!/^\d{1,9}$/.test(jwcode)) {
ElMessage.warning('精网号必须为数字且不超过九位');
ElMessage.warning(t('elmessage.limitJwcodeNine'));
resetForm()
return;
}
@ -445,7 +448,7 @@ const getUser = async function (jwcode) {
historyTaskGold: result.data.historyTaskGold
};
ElMessage.success("查询成功");
ElMessage.success(t('elmessage.searchSuccess'));
// sumGold
if (addConsume.value.sumGold) {
const parsedSumGold = parseFloat(addConsume.value.sumGold);
@ -461,16 +464,16 @@ const getUser = async function (jwcode) {
} else if (!result.data) {
ElMessage.warning("用户不存在");
ElMessage.warning(t('elmessage.noUser'));
user.value.jwcode = null
addConsume.value.jwcode = null
// resetForm(); //
} else {
ElMessage.warning(result.msg || "请检查查询参数");
ElMessage.warning(result.msg || t('elmessage.checkQueryParams'));
}
} catch (error) {
console.error("请求失败", error);
ElMessage.error("查询失败,请检查网络连接或精网号是否正确");
ElMessage.error(t('elmessage.queryFailed'));
resetForm(); //
}
};
@ -534,20 +537,22 @@ onMounted(async function () {
<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-form-item prop="jwcode" :label="t('common_add.jwcode')" 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 type="primary" @click="getUser(addConsume.jwcode)" style="margin-left: 20px">
{{ t('common.search') }}
</el-button>
</el-form-item>
<el-form-item prop="goodsName" label="商品名称">
<el-select v-model="addConsume.goodsName" placeholder="请选择商品" style="width: 200px" clearable filterable>
<el-form-item prop="goodsName" :label="t('common_add.goodsName')">
<el-select v-model="addConsume.goodsName" :placeholder="t('common_add.goodsNamePlaceholder')"
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-form-item prop="sumGold" :label="t('common_add.consumeTotalGold')">
<el-input v-model="addConsume.sumGold" style="width: 120px" @input="validateInput()"
@change="calculateCoins(addConsume.sumGold)" />
</el-form-item>
@ -555,21 +560,21 @@ onMounted(async function () {
<!-- 三类金币自动计算禁用状态不可编辑 -->
<el-form-item prop="permanentGold" label="永久金币">
<el-form-item prop="permanentGold" :label="t('common_add.permanentGold')">
<el-input v-model="addConsume.permanentGold" disabled style="width: 120px">
<template #default="scope">{{ scope.row.permanentGold }}</template>
</el-input>
<p style="margin-right: 0px">&nbsp;&nbsp;</p>
<p style="margin-right: 0px">&nbsp;&nbsp;{{ $t('common.') }}</p>
</el-form-item>
<el-form-item prop="freeCoin" label="免费金币">
<el-form-item prop="freeCoin" :label="t('common_add.freeGold')">
<el-input disabled v-model="addConsume.freeGold" style="width: 120px" />
<p style="margin-right: 0px">&nbsp;&nbsp;</p>
<p style="margin-right: 0px">&nbsp;&nbsp;{{ $t('common.') }}</p>
</el-form-item>
<el-form-item prop="taskGold" label="任务金币">
<el-form-item prop="taskGold" :label="t('common_add.taskGold')">
<el-input disabled v-model="addConsume.taskGold" style="width: 120px" />
<p style="margin-right: 20px">&nbsp;&nbsp;</p>
<p style="margin-right: 20px">&nbsp;&nbsp;{{ $t('common.') }}</p>
</el-form-item>
<el-form-item prop="remark" label="备注">
@ -577,8 +582,11 @@ onMounted(async function () {
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-button type="success" @click="resetForm()" style="margin-left: 200px;margin-top:10px">{{ t('common.reset')
}}</el-button>
<el-button type="primary" :disabled="addDisabled" @click="addBefore" style="margin-top:10px">{{
t('common.submit')
}}</el-button>
</el-form>
</div>
@ -586,28 +594,29 @@ onMounted(async function () {
<!-- 客户信息栏 -->
<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-text size="large" style="margin-left: 20px">{{ $t('common_add_user.customerInfo') }}</el-text>
<!-- 第一行姓名 + 历史金币 -->
<el-row style="margin-top: 20px">
<el-col :span="9">
<el-form-item label="姓名">
<el-form-item :label="$t('common_add_user.name')">
<p>{{ user.name }}</p>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="当前金币总数" style="width: 500px">
<el-form-item :label="$t('common_add_user.currentGoldCoinTotal')" 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">(永久金币:{{
<span style="color: #b1b1b1; margin-left: 0px" v-if="user.nowPermanentGold !== undefined">({{
$t('common_add_user.permanentGold') }}:{{
user.nowPermanentGold
}};
免费金币:{{ user.nowFreeGold }};
任务金币:{{ user.nowTaskGold }})</span>
{{ $t('common_add_user.freeGold') }}:{{ user.nowFreeGold }};
{{ $t('common_add_user.taskGold') }}:{{ user.nowTaskGold }})</span>
</el-form-item>
</el-col>
</el-row>
@ -615,16 +624,18 @@ onMounted(async function () {
<!-- 第二行精网号 + 当前金币独立行 -->
<el-row>
<el-col :span="9">
<el-form-item label="精网号">
<el-form-item :label="$t('common_add_user.jwcode')">
<p>{{ user.jwcode }}</p>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="消费次数">
<el-form-item :label="$t('common_add_user.consumptionTimes')">
<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>
<p style="font-size: small; color: #b1b1b1">({{ $t('common_add_user.onlyStatisticsDataAfter20250101')
}})
</p>
</el-form-item>
</el-col>
</el-row>
@ -644,7 +655,7 @@ onMounted(async function () {
<!-- 第四行消费次数 + 所属门店 -->
<el-row>
<el-col :span="9">
<el-form-item label="所属门店">
<el-form-item :label="$t('common_add_user.store')">
<p>{{ user.market }}</p>
</el-form-item>
</el-col>
@ -653,42 +664,42 @@ onMounted(async function () {
</el-card>
<el-dialog v-model="FirstConsumeDialogVisible" title="操作确认" :before-close="FirstConsumeDialogVisiblehandleClose"
:close-on-click-modal="false" width="480px">
<el-dialog v-model="FirstConsumeDialogVisible" :title="$t('common_add.operationConfirm')"
:before-close="FirstConsumeDialogVisiblehandleClose" :close-on-click-modal="false" width="480px">
<!-- 内容整体居中且收窄 -->
<div class="confirm-body">
<!-- 用户信息 -->
<div>
<div class="field-label">用户信息</div>
<div class="field-label">{{ $t('common_add.userInfo') }}</div>
<el-input :model-value="user.jwcode + (user.name ? '' + user.name + '' : '')" disabled />
</div>
<!-- 活动名称 -->
<!-- 商品名称 -->
<div class="field">
<div class="field-label">商品名称</div>
<div class="field-label">{{ $t('common_add.goodsName') }}</div>
<el-input v-model="addConsume.goodsName.value" disabled />
</div>
<!--金币总数 -->
<div class="field">
<div class="field-label">金币总数</div>
<div class="field-label">{{ $t('common_add.totalGold') }}</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>
<div class="field-label">{{ $t('common_add.permanentGold') }}</div>
<el-input v-model="addConsume.permanentGold" disabled />
</div>
</el-col>
<el-col :span="8">
<div class="field">
<div class="field-label">免费金币</div>
<div class="field-label">{{ $t('common_add.freeGold') }}</div>
<el-input v-model="addConsume.freeGold" disabled />
</div>
</el-col>
<el-col :span="8">
<div class="field">
<div class="field-label">任务金币</div>
<div class="field-label">{{ $t('common_add.taskGold') }}</div>
<el-input v-model="addConsume.taskGold" disabled />
</div>
</el-col>
@ -696,7 +707,7 @@ onMounted(async function () {
</el-row>
<div class="field">
<div class="field-label">备注</div>
<div class="field-label">{{ $t('common_add.remark') }}</div>
<el-input v-model="addConsume.remark" disabled />
</div>
</div>
@ -704,49 +715,49 @@ onMounted(async function () {
<!-- 底部按钮居中 -->
<template #footer>
<div class="dialog-footer-center">
<el-button @click="FirstConsumeDialogVisibleCancel"> </el-button>
<el-button type="primary" @click="FirstConsumeDialogVisibleContinue">确认购买</el-button>
<el-button @click="FirstConsumeDialogVisibleCancel">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="FirstConsumeDialogVisibleContinue">{{ $t('common.confirm') }}</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="ConsumeDialogVisible" title="操作确认" :before-close="ConsumeDialogVisiblehandleClose"
<el-dialog v-model="ConsumeDialogVisible" :title="$t('common_add.operationConfirm')" :before-close="ConsumeDialogVisiblehandleClose"
:close-on-click-modal="false" width="480px">
<!-- 内容整体居中且收窄 -->
<div class="confirm-body">
<!-- 用户信息 -->
<div>
<div class="field-label">用户信息</div>
<div class="field-label">{{ $t('common_add.userInfo') }}</div>
<el-input :model-value="user.jwcode + (user.name ? '' + user.name + '' : '')" disabled />
</div>
<!-- 活动名称 -->
<!-- 商品名称 -->
<div class="field">
<div class="field-label">商品名称</div>
<div class="field-label">{{ $t('common_add.goodsName') }}</div>
<el-input v-model="addConsume.goodsName.value" disabled />
</div>
<!--金币总数 -->
<div class="field">
<div class="field-label">金币总数</div>
<div class="field-label">{{ $t('common_add.totalGold') }}</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>
<div class="field-label">{{ $t('common_add.permanentGold') }}</div>
<el-input v-model="addConsume.permanentGold" disabled />
</div>
</el-col>
<el-col :span="8">
<div class="field">
<div class="field-label">免费金币</div>
<div class="field-label">{{ $t('common_add.freeGold') }}</div>
<el-input v-model="addConsume.freeGold" disabled />
</div>
</el-col>
<el-col :span="8">
<div class="field">
<div class="field-label">任务金币</div>
<div class="field-label">{{ $t('common_add.taskGold') }}</div>
<el-input v-model="addConsume.taskGold" disabled />
</div>
</el-col>
@ -757,16 +768,16 @@ onMounted(async function () {
<el-icon :size="24" color="#FFD700">
<WarnTriangleFilled />
</el-icon>
<p>重复购买风险提示</p>
<p>{{ $t('common_add.prompt') }}</p>
</div>
<!-- 记录 + 虚线分隔 -->
<div>
<el-divider border-style="dashed" />
<p>检测到该用户近期有相似消费记录</p>
· {{ ReadCookiesTime }} 购买 {{ addConsume.goodsName.value }}(操作人: {{ adminData.adminName }})
<p>{{ $t('common_add.similarRechargeRecords') }}</p>
· {{ ReadCookiesTime }} {{ $t('common_add.buy') }} {{ addConsume.goodsName.value }}({{ $t('common_add.operator') }}: {{ adminData.adminName }})
</div>
<div style="margin-top: 10px">
<p>是否继续操作</p>
<p>{{ $t('common_add.continueOperation') }}</p>
</div>
</div>
@ -774,8 +785,8 @@ onMounted(async function () {
<!-- 底部按钮居中 -->
<template #footer>
<div class="dialog-footer-center">
<el-button @click="ConsumeDialogVisibleCancel"> </el-button>
<el-button type="primary" @click="ConsumeDialogVisibleContinue">确认购买</el-button>
<el-button @click="ConsumeDialogVisibleCancel">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="ConsumeDialogVisibleContinue">{{ $t('common.confirm') }}</el-button>
</div>
</template>
</el-dialog>

5
src/views/consume/gold/coinConsume.vue

@ -9,7 +9,7 @@
@click="navigateTo('coinConsumeDetail')"
v-if="hasDetail"
>
金币消耗明细
{{ $t('consume.coinConsumeDetail') }}
</el-button>
<el-button
@ -18,7 +18,7 @@
@click="navigateTo('addCoinConsume')"
v-if="hasAdd"
>
新增消耗
{{ $t('consume.addCoinConsume') }}
</el-button>
</el-button-group>
</div>
@ -33,6 +33,7 @@ import { useRoute, useRouter } from 'vue-router';
import { storeToRefs } from "pinia";
import { useAdminStore } from "@/store/index.js";
import { hasMenuPermission, permissionMapping } from "@/utils/menuTreePermission.js";
import { useI18n } from 'vue-i18n';
const router = useRouter();
const route = useRoute();

127
src/views/consume/gold/coinConsumeDetail.vue

@ -9,6 +9,9 @@ import { storeToRefs } from 'pinia'
import { useAdminStore } from '@/store/index.js'
const adminStore = useAdminStore()
const { menuTree, flag } = storeToRefs(adminStore)
//
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
//
// flag
@ -104,28 +107,28 @@ const sortOrder = ref('')
const consumePlatform = [
{
value: '金币系统',
label: '金币系统'
label: t('consume.consumePlatforms.goldSystem')
},
{
value: 'HomilyChart',
label: 'HomilyChart'
label: t('consume.consumePlatforms.HomilyChart')
},
{
value: 'HomilyLink',
label: 'HomilyLink'
label: t('consume.consumePlatforms.HomilyLink')
},
{
value: 'ERP',
label: 'ERP'
label: t('consume.consumePlatforms.ERP')
},
{
value: '其他',
label: '其他'
label: t('consume.consumePlatforms.other')
},
{
value: '初始化金币',
label: '初始化金币'
label: t('consume.consumePlatforms.initGold')
},
]
@ -211,7 +214,7 @@ const ConsumeSelectBy = async function (val) {
//
if (!numberRegex.test(consumeUser.value.jwcode)) {
ElMessage.error('请检查精网号格式')
ElMessage.error(t('elmessage.checkJwcodeFormat'))
return
}
}
@ -453,7 +456,7 @@ const exportExcel = async function () {
}
const res = await API({ url: '/export/exportConsume', data: params })
if (res.code === 200) {
ElMessage.success('导出成功')
ElMessage.success(t('elmessage.exportSuccess'))
}
}
const exportListVisible = ref(false)
@ -479,11 +482,11 @@ const getExportList = async () => {
});
exportList.value = filteredData
} else {
ElMessage.error(result.msg || '获取导出列表失败')
ElMessage.error(result.msg || t('elmessage.getExportListError'))
}
} catch (error) {
console.error('获取导出列表出错:', error)
ElMessage.error('获取导出列表失败,请稍后重试')
ElMessage.error(t('elmessage.getExportListError'))
} finally {
exportListLoading.value = false
}
@ -496,7 +499,7 @@ const downloadExportFile = (item) => {
link.download = item.fileName
link.click()
} else {
ElMessage.warning('文件还在导出中,请稍后再试')
ElMessage.warning(t('elmessage.exportingInProgress'))
}
}
//
@ -518,15 +521,15 @@ const getTagType = (state) => {
const getTagText = (state) => {
switch (state) {
case 0:
return '待执行';
return t('elmessage.pendingExecution');
case 1:
return '执行中';
return t('elmessage.executing');
case 2:
return '执行完成';
return t('elmessage.executed');
case 3:
return '执行出错';
return t('elmessage.errorExecution');
default:
return '未知状态';
return t('elmessage.unknownStatus');
}
}
//
@ -583,24 +586,24 @@ const getMarket = async function () {
<el-col style="margin-bottom: 1vh">
<div class="select">
<div class="selectRow">
<el-text class="text" size="large">精网号</el-text>
<el-input class="selectContent" v-model="consumeUser.jwcode" placeholder="请输入精网号" clearable />
<el-text class="text" size="large">{{ $t('common.jwcode') }}</el-text>
<el-input class="selectContent" v-model="consumeUser.jwcode" :placeholder="$t('common.jwcodePlaceholder')" clearable />
</div>
<div class="selectRow">
<el-text class="text" size="large">商品名称</el-text>
<el-select class="selectContent" v-model="consumeUser.goodsName" placeholder="请选择商品名称" clearable filterable>
<el-text class="text" size="large">{{ $t('common.goodsName') }}</el-text>
<el-select class="selectContent" v-model="consumeUser.goodsName" :placeholder="$t('common.goodsNamePlaceholder')" clearable filterable>
<el-option v-for="(item, index) in goods" :key="index" :label="item.label" :value="item" />
</el-select>
</div>
<div class="selectRow" style="width: 15vw;">
<el-text size="large">所属地区</el-text>
<el-cascader class="selectContent" style="width: 8vw;" v-model="selectedMarketPath" :options="market" placeholder="请选择所属地区"
<el-text size="large">{{ $t('common.market') }}</el-text>
<el-cascader class="selectContent" style="width: 8vw;" v-model="selectedMarketPath" :options="market" :placeholder="$t('common.marketPlaceholder')"
clearable @change="handleMarketChange" />
</div>
<div class="selectRow" style="width: 15vw;">
<el-text size="large">消耗平台</el-text>
<el-select class="selectContent" v-model="consumeUser.payPlatform" placeholder="请选择消耗平台" clearable>
<el-text size="large">{{ $t('common.consumePlatform') }}</el-text>
<el-select class="selectContent" v-model="consumeUser.payPlatform" :placeholder="$t('common.consumePlatformPlaceholder')" clearable>
<el-option v-for="item in consumePlatform" :key="item.id" :label="item.label" :value="item.value" />
</el-select>
</div>
@ -612,9 +615,9 @@ const getMarket = async function () {
<el-col>
<div class="select">
<div class="selectRow" style="width: 36vw;">
<el-text class="text" size="large">消耗时间</el-text>
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" range-separator=""
start-placeholder="起始时间" end-placeholder="结束时间" style="margin-right:1vw;width:25vw"
<el-text class="text" size="large">{{ $t('common.consumeTime') }}</el-text>
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" :range-separator="$t('common.to')"
:start-placeholder="$t('common.startTime')" :end-placeholder="$t('common.endTime')" style="margin-right:1vw;width:25vw"
@change="handleDatePickerChange" :default-time="defaultTime" :disabled-date="disabledDate" />
<div v-if="false">
@ -632,44 +635,44 @@ const getMarket = async function () {
</div>
</div>
<div class="selectRow" style="justify-content: flex-start;">
<el-button type="primary" @click="search()">查询</el-button>
<el-button type="primary" @click="exportExcel()">导出excel</el-button>
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">{{ $t('common.search') }}</el-button>
<el-button type="primary" @click="exportExcel()">{{ $t('common.exportExcel') }}</el-button>
<el-button type="primary" @click="openExportList">{{ $t('common.viewExportList') }}</el-button>
<el-button type="success" @click="reset()">{{ $t('common.reset') }}</el-button>
</div>
</div>
</el-col>
</el-card>
<el-card class="card2">
<div class="goldStatistics">
消耗新币{{ format3(Math.abs(permanentGolds)) }}新币&nbsp;&nbsp;&nbsp;&nbsp;
总金币数{{ format3(Math.abs(permanentGolds + freeGolds + taskGolds)) }}&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(Math.abs(permanentGolds)) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金币{{ format3(Math.abs(freeGolds)) }}&nbsp;&nbsp;&nbsp;&nbsp;
任务金币{{ format3(Math.abs(taskGolds)) }}
{{ $t('common.consumeSGD') }}{{ format3(Math.abs(permanentGolds)) }} {{ $t('common.SGD') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('common.totalGoldCoin') }}{{ format3(Math.abs(permanentGolds + freeGolds + taskGolds)) }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('common.permanentGold') }}{{ format3(Math.abs(permanentGolds)) }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('common.freeGold') }}{{ format3(Math.abs(freeGolds)) }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('common.taskGold') }}{{ format3(Math.abs(taskGolds)) }}
</div>
<div style="height: 65vh;">
<el-table :data="tableData" style="height: 65vh" @sort-change="handleSortChange"
:row-style="{ height: '50px' }">
<el-table-column type="index" label="序号" width="80px" fixed="left">
<el-table-column type="index" :label="$t('common_list.id')" width="80px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column prop="name" label="姓名" width="150px" fixed="left" show-overflow-tooltip />
<el-table-column prop="jwcode" label="精网号" width="110px" fixed="left" />
<el-table-column prop="market" label="所属地区" width="110px" />
<el-table-column prop="orderCode" label="订单号" width="260px" show-overflow-tooltip />
<el-table-column prop="goodsName" label="商品名称" width="160px" show-overflow-tooltip />
<el-table-column prop="payPlatform" label="消耗平台" width="120px">
<el-table-column prop="name" :label="$t('common_list.name')" width="150px" fixed="left" show-overflow-tooltip />
<el-table-column prop="jwcode" :label="$t('common_list.jwcode')" width="110px" fixed="left" />
<el-table-column prop="market" :label="$t('common_list.market')" width="110px" />
<el-table-column prop="orderCode" :label="$t('common_list.orderNo')" width="260px" show-overflow-tooltip />
_list
<el-table-column prop="goodsName" :label="$t('common_list.goodsName')" width="160px" show-overflow-tooltip />
<el-table-column prop="payPlatform" :label="$t('common_list.consumePlatform')" width="120px">
<template #default="scope">
{{ scope.row.payPlatform }}
</template>
</el-table-column>
<el-table-column prop="sumGold" label="消耗金币总数" width="120px">
<el-table-column prop="sumGold" :label="$t('common_list.consumeTotalGold')" width="120px">
<template #default="scope">
{{
(scope.row.taskGold +
@ -679,32 +682,32 @@ const getMarket = async function () {
</template>
</el-table-column>
<el-table-column prop="permanentGold" label="永久金币" sortable="“custom”" width="110px">
<el-table-column prop="permanentGold" :label="$t('common_list.permanentGold')" sortable="“custom”" width="110px">
<template #default="scope">
{{ scope.row.permanentGold }}
</template>
</el-table-column>
<el-table-column prop="freeGold" label="免费金币" sortable="“custom”" width="110px">
<el-table-column prop="freeGold" :label="$t('common_list.freeGold')" sortable="“custom”" width="110px">
<template #default="scope">
{{ scope.row.freeGold }}
</template>
</el-table-column>
<el-table-column prop="taskGold" label="任务金币" sortable="“custom”" width="110px">
<el-table-column prop="taskGold" :label="$t('common_list.taskGold')" sortable="“custom”" width="110px">
<template #default="scope">
{{ scope.row.taskGold }}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" width="200px" show-overflow-tooltip />
<el-table-column prop="isRefund" label="订单状态" width="200px" show-overflow-tooltip>
<el-table-column prop="remark" :label="$t('common_list.remark')" width="200px" show-overflow-tooltip />
<el-table-column prop="isRefund" :label="$t('common_list.orderStatus')" width="200px" show-overflow-tooltip>
<template #default="scope">
<span v-if="scope.row.isRefund == 0">正常</span>
<span v-else-if="scope.row.isRefund == 1">已退款</span>
<span v-else>未知状态</span>
<span v-if="scope.row.isRefund == 0">{{ $t('consume.normal') }}</span>
<span v-else-if="scope.row.isRefund == 1">{{ $t('consume.refunded') }}</span>
<span v-else>{{ $t('consume.unknown') }}</span>
</template>
</el-table-column>
<el-table-column prop="adminName" label="提交人" width="110px" />
<el-table-column prop="createTime" label="消耗时间" sortable="custom" width="180px" />
<el-table-column prop="adminName" :label="$t('common_list.submitter')" width="110px" />
<el-table-column prop="createTime" :label="$t('common_list.consumeTime')" sortable="custom" width="180px" />
</el-table>
</div>
@ -717,33 +720,33 @@ const getMarket = async function () {
</el-card>
<!-- 导出弹窗 -->
<el-dialog v-model="exportListVisible" title="导出列表" width="80%">
<el-dialog v-model="exportListVisible" :title="$t('common_export.exportList')" width="80%">
<el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
<el-table-column prop="fileName" label="文件名" />
<el-table-column prop="state" label="状态">
<el-table-column prop="fileName" :label="$t('common_export.fileName')" />
<el-table-column prop="state" :label="$t('common_export.status')">
<template #default="scope">
<el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
{{ getTagText(scope.row.state) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间">
<el-table-column prop="createTime" :label="$t('common_export.createTime')">
<template #default="scope">
{{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作">
<el-table-column :label="$t('common_export.operation')">
<template #default="scope">
<el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
:disabled="scope.row.state !== 2">
下载
{{ $t('common_export.download') }}
</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button text @click="exportListVisible = false">关闭</el-button>
<el-button text @click="exportListVisible = false">{{ $t('common_export.close') }}</el-button>
</div>
</template>
</el-dialog>

18
src/views/home.vue

@ -3,6 +3,7 @@ import {computed, onMounted, ref} from 'vue'
import {useRoute, useRouter} from 'vue-router'
import {ElMessage} from 'element-plus'
import ChangePassword from '@/components/dialogs/changePassword.vue'
import LanguageSwitch from '@/components/dialogs/LanguageSwitch.vue' //
import {useAdminStore} from '@/store'
import {storeToRefs} from 'pinia'
import {filterMenu, getRoutePath} from "@/utils/menuUtils.js";
@ -27,6 +28,7 @@ const menuNameMap = {
'活动管理': 'activity-management',
'频道管理': 'channel-management',
'权限管理': 'permission-management',
'多语言配置': 'mutiple-language',
}
const getIconPath = (menuName) => {
@ -46,6 +48,17 @@ const getIconPath = (menuName) => {
}
}
// ------------------ ------------------
const languageSwitchRef = ref()
const openLanguageSwitch = () => {
languageSwitchRef.value?.open()
}
const handleLanguageChanged = (lang) => {
ElMessage.success(`语言已切换到${lang}`)
}
// ------------------ ------------------
const refreshData = async () => {
try {
@ -74,7 +87,6 @@ const adminStore = useAdminStore()
const {adminData, menuTree, flag} = storeToRefs(adminStore)
const menuList = ref(filterMenu(menuTree.value))
function findBestMatch(menuList, path) {
let bestMatch = ''
@ -368,7 +380,7 @@ onMounted(() => getMessage())
<template #dropdown>
<el-dropdown-menu>
<!-- <el-dropdown-item @click="refreshData()">数据刷新</el-dropdown-item>-->
<!-- 员工数据开关 -->
<el-dropdown-item @click="openLanguageSwitch">语言切换</el-dropdown-item>
<el-dropdown-item @click="toggleFlag()">
{{ flag === 1 ? '显示员工数据' : '隐藏员工数据' }}
</el-dropdown-item>
@ -524,6 +536,8 @@ onMounted(() => getMessage())
</el-dialog>
<!-- 语言切换弹窗 -->
<LanguageSwitch ref="languageSwitchRef" />
</div>
</template>

535
src/views/language/languageTranslate.vue

@ -0,0 +1,535 @@
<template>
<!-- 筛选与搜索区域 -->
<el-card class="card1" style="margin-bottom: 1vh;">
<div class="condition">
<div class="condition-item">
<el-text size="large">搜索</el-text>
<el-input v-model="searchForm.chineseSimplified" style="width: 12vw" placeholder="请输入原文内容" clearable />
</div>
<!-- 移除语言状态筛选 -->
<div class="btn">
<el-button type="primary" @click="search">搜索</el-button>
<el-button type="success" @click="reset">重置</el-button>
</div>
</div>
</el-card>
<el-card class="card2">
<!-- 功能按钮区域 -->
<div class="add-item">
<el-button type="success" @click="handleAdd">添加</el-button>
<el-button class="add-item-export" @click="handleBatchImport">批量导入</el-button>
</div>
<div>
<el-table :data="tableData" style="width: 82vw;height:70vh;" :row-style="{ height: '50px' }">
<el-table-column type="index" label="序号" width="80px" fixed="left">
<template #default="scope">
<span>{{ scope.$index + 1 + (pagination.pageNum - 1) * pagination.pageSize }}</span>
</template>
</el-table-column>
<el-table-column prop="chineseSimplified" label="原文(中文)" width="180px" >
<template #default="scope">
<el-tooltip :content="scope.row.chineseSimplified" placement="top"
v-if="scope.row.chineseSimplified && scope.row.chineseSimplified.length > 20">
<span>{{ truncateText(scope.row.chineseSimplified) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.chineseSimplified }}</span>
</template>
</el-table-column>
<el-table-column prop="english" label="英文" width="180px" header-align="center">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tooltip :content="scope.row.english" placement="top"
v-if="scope.row.english && scope.row.english.length > 15">
<span>{{ truncateText(scope.row.english) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.english }}</span>
</div>
<el-tag :type="scope.row.english ? 'success' : 'info'" size="small" style="margin-left: 8px;">
{{ scope.row.english ? '已翻译' : '未翻译' }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="thai" label="泰语" width="180px" header-align="center">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tooltip :content="scope.row.thai" placement="top"
v-if="scope.row.thai && scope.row.thai.length > 15">
<span>{{ truncateText(scope.row.thai) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.thai }}</span>
</div>
<el-tag :type="scope.row.thai ? 'success' : 'info'" size="small" style="margin-left: 8px;">
{{ scope.row.thai ? '已翻译' : '未翻译' }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="chineseTraditional" label="繁体中文" width="150px" header-align="center">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tooltip :content="scope.row.chineseTraditional" placement="top"
v-if="scope.row.chineseTraditional && scope.row.chineseTraditional.length > 15">
<span>{{ truncateText(scope.row.chineseTraditional) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.chineseTraditional }}</span>
</div>
<el-tag :type="scope.row.chineseTraditional ? 'success' : 'info'" size="small" style="margin-left: 8px;">
{{ scope.row.chineseTraditional ? '已翻译' : '未翻译' }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="malay" label="马来语" width="150px" header-align="center">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tooltip :content="scope.row.malay" placement="top"
v-if="scope.row.malay && scope.row.malay.length > 15">
<span>{{ truncateText(scope.row.malay) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.malay }}</span>
</div>
<el-tag :type="scope.row.malay ? 'success' : 'info'" size="small" style="margin-left: 8px;">
{{ scope.row.malay ? '已翻译' : '未翻译' }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column prop="vietnamese" label="越南语" width="150px" header-align="center">
<template #default="scope">
<div style="display: flex; align-items: center; justify-content: space-between;">
<div style="flex: 1;">
<el-tooltip :content="scope.row.vietnamese" placement="top"
v-if="scope.row.vietnamese && scope.row.vietnamese.length > 15">
<span>{{ truncateText(scope.row.vietnamese) }}</span>
</el-tooltip>
<span v-else>{{ scope.row.vietnamese }}</span>
</div>
<el-tag :type="scope.row.vietnamese ? 'success' : 'info'" size="small" style="margin-left: 8px;">
{{ scope.row.vietnamese ? '已翻译' : '未翻译' }}
</el-tag>
</div>
</template>
</el-table-column>
<!-- 移除状态列 -->
<el-table-column prop="configTime" label="配置时间" width="180px" header-align="center">
<template #default="scope">
{{ moment(scope.row.configTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column prop="operation" label="操作" width="155px" fixed="right" header-align="center">
<template #default="scope">
<div style="display:flex; justify-content:center; ">
<el-button type="primary" text @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="danger" text @click="handleDelete(scope.row)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页组件 -->
<div style="margin-top: 20px;display: flex;">
<el-pagination background v-model:current-page="pagination.pageNum" v-model:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="pagination.total" style="margin-top: 1vh;"
@size-change="handleSizeChange" @current-change="handleCurrentChange" />
</div>
</el-card>
<!-- 确认删除对话框 -->
<ConfirmDialog
v-model="showDeleteDialog"
message="删除该翻译记录!"
@confirm="handleDeleteConfirm"
@cancel="handleDeleteCancel"
@close="handleDeleteClose"
/>
<!-- 编辑对话框 -->
<el-dialog v-model="showEditDialog" :title="editForm.id ? '编辑翻译' : '新增翻译'" width="30vw" draggable>
<el-form :model="editForm" label-width="120px">
<el-form-item label="原文(中文):">
<el-input v-model="editForm.chineseSimplified" placeholder="请输入原文内容" show-word-limit />
</el-form-item>
<el-form-item label="英文:">
<el-input v-model="editForm.english" placeholder="请输入英文翻译" show-word-limit />
</el-form-item>
<el-form-item label="泰语:">
<el-input v-model="editForm.thai" placeholder="请输入泰语翻译" show-word-limit />
</el-form-item>
<el-form-item label="繁体中文:">
<el-input v-model="editForm.chineseTraditional" placeholder="请输入繁体中文翻译"
show-word-limit />
</el-form-item>
<el-form-item label="马来语:">
<el-input v-model="editForm.malay" placeholder="请输入马来语翻译" show-word-limit />
</el-form-item>
<el-form-item label="越南语:">
<el-input v-model="editForm.vietnamese" placeholder="请输入越南语翻译" show-word-limit />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="showEditDialog = false">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
</template>
</el-dialog>
<!-- 批量导入对话框 -->
<el-dialog v-model="showImportDialog" title="批量导入" width="40vw" draggable>
<div style="margin-bottom: 20px;">
<el-text>下载导入模板</el-text>
<el-button type="text" @click="downloadTemplate">中文/英文/泰语/繁体中文/马来语/越南语模板</el-button>
</div>
<el-upload class="upload-demo" drag action="#" :auto-upload="false" :on-change="handleFileChange"
:show-file-list="false">
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
</el-upload>
<template #footer>
<el-button @click="showImportDialog = false">取消</el-button>
<el-button type="primary" @click="handleImport">导入</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ElMessage, ElMessageBox } from 'element-plus';
import { onMounted, ref, computed } from 'vue'
import API from "@/util/http.js"
import moment from 'moment'
import { UploadFilled } from '@element-plus/icons-vue'
import ConfirmDialog from '@/components/dialogs/ConfirmDialog.vue'
//
const tableData = ref([])
const pagination = ref({
pageNum: 1,
pageSize: 20,
total: 0
})
const searchForm = ref({
chineseSimplified: '',
// languageStatus
})
const showEditDialog = ref(false)
const showImportDialog = ref(false)
const showDeleteDialog = ref(false)
const currentDeleteRow = ref(null) //
const editForm = ref({
id: '',
chineseSimplified: '',
english: '',
thai: '',
chineseTraditional: '',
malay: '',
vietnamese: '',
// modules: [],
configTime: new Date()
})
// -
// const translationStatus = computed(() => {
// return (row) => {
// const hasTranslation = row.english || row.thai || row.chineseTraditional || row.malay || row.vietnamese
// return hasTranslation ? 'translated' : 'untranslated'
// }
// })
//
const truncateText = (text) => {
if (!text) return ''
return text.length > 20 ? text.substring(0, 20) + '...' : text
}
// getStatusType
// const getStatusType = (status) => {
// return status === 'translated' ? 'success' : 'info'
// }
//
const search = async () => {
await getTranslationList()
}
//
const reset = () => {
searchForm.value = {
chineseSimplified: '',
// languageStatus
}
getTranslationList()
}
//
const getTranslationList = async () => {
try {
const params = {
pageNum: pagination.value.pageNum,
pageSize: pagination.value.pageSize,
...searchForm.value
}
// API
const res = await API({
url: '/language/getTranslation',
data: params
})
if (res.code === 200) {
//
tableData.value = res.data.list
pagination.value.total = res.data.total
}
} catch (error) {
console.error('获取翻译列表失败:', error)
ElMessage.error('获取数据失败')
}
}
//
const handleEdit = (row) => {
editForm.value = { ...row }
showEditDialog.value = true
}
//
const handleAdd = () => {
editForm.value = {
id: '',
chineseSimplified: '',
english: '',
thai: '',
chineseTraditional: '',
malay: '',
vietnamese: '',
// modules: [],
configTime: new Date()
}
showEditDialog.value = true
}
//
const handleSave = async () => {
//
if (!editForm.value.chineseSimplified || editForm.value.chineseSimplified.trim() === '') {
ElMessage.error('原文为必填项')
return
}
//
const fields = ['english', 'thai', 'chineseTraditional', 'malay', 'vietnamese']
for (const field of fields) {
if (editForm.value[field] && /<[^>]*>/.test(editForm.value[field])) {
ElMessage.error('译文仅支持纯文本,不支持HTML标签')
return
}
}
try {
const url = editForm.value.id ? '/language/updateTranslation' : '/language/addTranslation'
const res = await API({
url: url,
data: editForm.value
})
if (res.code === 200) {
ElMessage.success(editForm.value.id ? '编辑成功' : '添加成功')
showEditDialog.value = false
getTranslationList()
} else if (res.code === 0) {
//
ElMessage.error(res.msg || '操作失败')
} else {
//
ElMessage.error(res.msg || '操作失败')
}
} catch (error) {
console.error('保存失败:', error)
ElMessage.error('保存失败')
}
}
// -
const handleDelete = (row) => {
currentDeleteRow.value = row
showDeleteDialog.value = true
}
//
const handleDeleteConfirm = async () => {
try {
const res = await API({
url: '/language/deleteTranslation',
data: { id: currentDeleteRow.value.id }
})
if (res.code === 200) {
ElMessage.success('删除成功')
getTranslationList()
}
} catch (error) {
console.error('删除失败:', error)
ElMessage.error('删除失败')
} finally {
showDeleteDialog.value = false
currentDeleteRow.value = null
}
}
//
const handleDeleteCancel = () => {
showDeleteDialog.value = false
currentDeleteRow.value = null
}
//
const handleDeleteClose = () => {
showDeleteDialog.value = false
currentDeleteRow.value = null
}
//
const handleBatchImport = () => {
showImportDialog.value = true
}
//
const downloadTemplate = () => {
//
ElMessage.info('模板下载功能待实现')
}
//
const handleFileChange = (file) => {
//
console.log('文件变化:', file)
}
//
const handleImport = () => {
//
ElMessage.info('导入功能待实现')
}
//
const handleSizeChange = (val) => {
pagination.value.pageSize = val
pagination.value.pageNum = 1
getTranslationList()
}
const handleCurrentChange = (val) => {
pagination.value.pageNum = val
getTranslationList()
}
//
onMounted(() => {
getTranslationList()
})
</script>
<style scoped lang="scss">
// -
.card1 {
background: #F3FAFE;
}
// -
.card2 {
background: #E7F4FD;
}
// -
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.condition {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.condition-item {
display: flex;
align-items: center;
min-width: 180px;
}
.btn {
display: flex;
align-items: center;
gap: 4px;
}
.add-item {
display: flex;
align-items: center;
gap: 4px;
margin-bottom: 1vh;
.add-item-export {
background-color: #5870FF;
color: white;
}
}
//
.el-tag {
border: none;
}
//
.upload-demo {
width: 100%;
}
:deep(.el-upload-dragger) {
width: 100%;
height: 180px;
}
</style>

197
src/views/recharge/gold/addCoinRecharge.vue

@ -7,6 +7,9 @@ import API from '@/util/http.js'
import moment from 'moment'
import Cookies from 'js-cookie';
import Decimal from 'decimal.js';
//
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
// fixedAdminId
// const fixedAdminId = 1;
@ -23,11 +26,11 @@ const beforeAvatarUpload = (file) => {
const isLt1M = file.size / 1024 / 1024 < 1;
if (!isImage) {
ElMessage.error('只能上传 JPG/PNG 图片!');
ElMessage.error(t('elmessage.onlyUploadJPGPNG'));
return false;
}
if (!isLt1M) {
ElMessage.error('图片大小不能超过 1MB!');
ElMessage.error(t('elmessage.limitImageSize'));
return false;
}
return true;
@ -124,7 +127,7 @@ const add = async function () {
//
console.log('请求成功', result)
//
ElMessage.success('添加成功')
ElMessage.success(t('elmessage.addSuccess'))
//
deleteRecharge()
user.value = {}
@ -199,7 +202,7 @@ const addBefore = () => {
if (!valid) {
ElMessage({
type: 'error',
message: '请检查输入内容'
message: t('elmessage.checkInputContent')
});
return;
}
@ -208,7 +211,7 @@ const addBefore = () => {
if (Number(recharge.value.permanentGold) === 0 && Number(recharge.value.freeGold) === 0) {
ElMessage({
type: 'error',
message: '永久金币和免费金币不能同时为0'
message: t('elmessage.permanentAndFreeNoZero')
});
return;
}
@ -217,7 +220,7 @@ const addBefore = () => {
if (!recharge.value.rateName) {
ElMessage({
type: 'error',
message: '请选择币种'
message: t('elmessage.checkRate')
});
return;
}
@ -226,7 +229,7 @@ const addBefore = () => {
if (!recharge.value.money) {
ElMessage({
type: 'error',
message: '请输入充值金额'
message: t('elmessage.checkMoney')
});
return;
}
@ -240,7 +243,7 @@ const addBefore = () => {
//
if (!user.value.jwcode) {
ElMessage.warning('请先查询用户信息')
ElMessage.warning(t('elmessage.checkUserInfo'))
return
}
@ -270,19 +273,19 @@ const rules = reactive({
jwcode: [{
required: true, validator: (rule, value, callback) => {
if (!value) {
callback(new Error('精网号不能为空'));
callback(new Error(t('elmessage.noEmptyJwcode')));
return;
}
if (/[^0-9]/.test(value)) {
callback(new Error('精网号只能包含数字'));
callback(new Error(t('elmessage.limitDigitJwcode')));
return;
}
callback();
}, trigger: 'blur'
}],
activity: [{required: true, message: '请输入活动名称', trigger: 'blur'}],
activity: [{required: true, message: t('elmessage.checkActivity'), trigger: 'blur'}],
permanentGold: [
{required: true, message: '请输入永久金币数', trigger: 'change'},
{required: true, message: t('elmessage.checkPermanentGold'), trigger: 'change'},
{
validator: (rule, value, callback) => {
if (!value) {
@ -290,14 +293,14 @@ const rules = reactive({
}
//
if (/[^0-9.]/.test(value)) {
callback(new Error('不能包含特殊符号或负数'));
callback(new Error(t('elmessage.limitNoSpecialChar')));
return;
}
//
const integerPart = value.split('.')[0];
if (integerPart.length > 6) {
callback(new Error('整数位数不能超过6位'));
callback(new Error(t('elmessage.limitSix')));
return;
}
@ -305,16 +308,16 @@ const rules = reactive({
if (value.includes('.')) {
const decimalPart = value.split('.')[1];
if (decimalPart.length > 2) {
callback(new Error('小数位数不能超过两位'));
callback(new Error(t('elmessage.limitTwoDecimal')));
return;
}
}
const numValue = Number(value);
if (isNaN(numValue)) {
callback(new Error('请输入有效的数字'));
callback(new Error(t('elmessage.checkNumber')));
} else if (numValue < 0) {
callback(new Error('输入金额不能小于0'));
callback(new Error(t('elmessage.limitZero')));
} else {
callback();
}
@ -323,7 +326,7 @@ const rules = reactive({
}
],
freeGold: [
{required: true, message: '请输入免费金币数', trigger: 'change'},
{required: true, message: t('elmessage.checkFreeGold'), trigger: 'change'},
{
validator: (rule, value, callback) => {
if (!value) {
@ -331,14 +334,14 @@ const rules = reactive({
}
//
if (/[^0-9.]/.test(value)) {
callback(new Error('不能包含特殊符号或负数'));
callback(new Error(t('elmessage.limitNoSpecialChar')));
return;
}
//
const integerPart = value.split('.')[0];
if (integerPart.length > 6) {
callback(new Error('整数位数不能超过6位'));
callback(new Error(t('elmessage.limitSix')));
return;
}
@ -346,16 +349,16 @@ const rules = reactive({
if (value.includes('.')) {
const decimalPart = value.split('.')[1];
if (decimalPart.length > 2) {
callback(new Error('小数位数不能超过两位'));
callback(new Error(t('elmessage.limitTwoDecimal')));
return;
}
}
const numValue = Number(value);
if (isNaN(numValue)) {
callback(new Error('请输入有效的数字'));
callback(new Error(t('elmessage.checkNumber')));
} else if (numValue < 0) {
callback(new Error('输入金额不能小于0'));
callback(new Error(t('elmessage.limitZero')));
} else {
callback();
}
@ -365,24 +368,24 @@ const rules = reactive({
],
rateName: [{
required: true,
message: '请选择货币名称',
message: t('elmessage.checkRate'),
trigger: 'blur'
}],
money: [
{required: true, message: '请输入充值金额', trigger: 'blur'},
{required: true, message: t('elmessage.checkMoney'), trigger: 'blur'},
{
validator: (rule, value, callback) => {
//
if (/[^0-9.]/.test(value)) {
callback(new Error('不能包含特殊符号或负数'));
callback(new Error(t('elmessage.limitNoSpecialChar')));
return;
}
//
const integerPart = value.split('.')[0];
if (integerPart.length > 6) {
callback(new Error('整数位数不能超过6位'));
callback(new Error(t('elmessage.limitSix')));
return;
}
@ -390,16 +393,16 @@ const rules = reactive({
if (value.includes('.')) {
const decimalPart = value.split('.')[1];
if (decimalPart.length > 2) {
callback(new Error('小数位数不能超过两位'));
callback(new Error(t('elmessage.limitTwoDecimal')));
return;
}
}
const numValue = Number(value);
if (isNaN(numValue)) {
callback(new Error('请输入有效的数字'));
callback(new Error(t('elmessage.checkNumber')));
} else if (numValue < 0) {
callback(new Error('输入金额不能小于0'));
callback(new Error(t('elmessage.limitZero')));
} else {
callback();
}
@ -407,8 +410,8 @@ const rules = reactive({
trigger: 'blur'
}
],
payModel: [{required: true, message: '请选择付款方式', trigger: 'blur'}],
payTime: [{required: true, message: '请选择交款时间', trigger: 'blur'}]
payModel: [{required: true, message: t('elmessage.checkPayModel'), trigger: 'blur'}],
payTime: [{required: true, message: t('elmessage.checkPayTime'), trigger: 'blur'}]
});
//
@ -417,13 +420,13 @@ const getUser = async function (jwcode) {
trimJwCode();
//
if (!jwcode) {
ElMessage.warning('精网号不能为空');
ElMessage.warning(t('elmessage.noEmptyJwcode'));
return;
}
//
if (!/^\d{1,9}$/.test(jwcode)) {
ElMessage.warning('精网号必须为数字且不超过九位');
ElMessage.warning(t('elmessage.limitJwcodeNine'));
deleteRecharge()
return;
}
@ -440,15 +443,15 @@ const getUser = async function (jwcode) {
if (result.code === 0) {
ElMessage.error(result.msg);
} else if (result.data === null) {
ElMessage.error("用户不存在");
ElMessage.error(t('elmessage.noUser'));
} else {
user.value = result.data;
console.log("用户信息", user.value);
ElMessage.success("查询成功");
ElMessage.success(t('elmessage.searchSuccess'));
}
} catch (error) {
console.log("请求失败", error);
ElMessage.error("精网号错误");
ElMessage.error(t('elmessage.jwcodeError'));
}
}
@ -515,13 +518,13 @@ const customUpload = async (options) => {
if (response.data.code === 200 && response.data.data) {
//
handleAvatarSuccess(response.data, options.file);
ElMessage.success('上传成功');
ElMessage.success(t('elmessage.uploadSuccess'));
} else {
ElMessage.error(response.data.msg || '上传失败');
ElMessage.error(response.data.msg || t('elmessage.uploadFailed'));
}
} catch (error) {
console.error('上传错误:', error);
ElMessage.error(`上传失败: ${error.response?.data?.message || error.message}`);
ElMessage.error(`${t('elmessage.uploadFailed')}: ${error.response?.data?.message || error.message}`);
}
};
@ -550,47 +553,47 @@ const handleAvatarSuccess = (response, file) => {
const payModel = [
{
value: '银行转账',
label: '银行转账'
label: t('audit.payMethods.bankTransfer')
},
{
value: '现金',
label: '现金'
label: t('audit.payMethods.cash')
},
{
value: '支票',
label: '支票'
label: t('audit.payMethods.check')
},
{
value: '刷卡',
label: '刷卡'
label: t('audit.payMethods.card')
},
{
value: 'Grabpay',
label: 'Grabpay'
label: t('audit.payMethods.grabpay')
},
{
value: 'Nets',
label: 'Nets'
label: t('audit.payMethods.nets')
},
{
value: 'PayPal',
label: 'PayPal'
label: t('audit.payMethods.paypal')
},
{
value: 'Stripe-链接收款',
label: 'Stripe-链接收款'
label: t('audit.payMethods.stripe')
},
{
value: 'Ipay88-链接收款',
label: 'Ipay88-链接收款'
label: t('audit.payMethods.ipay88')
},
{
value: 'PaymentAsia-链接收款',
label: 'PaymentAsia-链接收款'
label: t('audit.payMethods.paymentAsia')
},
{
value: '其他',
label: '其他'
label: t('audit.payMethods.other')
}
]
@ -640,24 +643,24 @@ onMounted(() => {
<div class="left">
<el-form :model="recharge" ref="Ref" :rules="rules" label-width="auto" label-position="right"
style="min-width: 420px" class="add-form">
<el-form-item prop="jwcode" label="精网号">
<el-form-item prop="jwcode" :label="$t('common_add.jwcode')">
<el-input v-model="recharge.jwcode" style="width: 220px"/>
<el-button type="primary" @click="getUser(recharge.jwcode)" style="margin-left: 20px">查询</el-button>
<el-button type="primary" @click="getUser(recharge.jwcode)" style="margin-left: 20px">{{ $t('common.search') }}</el-button>
</el-form-item>
<el-form-item prop="activity" label="活动名称">
<el-input v-model="recharge.activity" placeholder="请输入活动名称" style="width: 300px"/>
<el-form-item prop="activity" :label="$t('common_add.activity')">
<el-input v-model="recharge.activity" :placeholder="$t('common_add.activityPlaceholder')" style="width: 300px"/>
</el-form-item>
<el-form-item prop="permanentGold" label="永久金币">
<el-form-item prop="permanentGold" :label="$t('common_add.permanentGold')">
<el-input v-model="recharge.permanentGold" placeholder="0" style="width: 100px"/>
<p>&nbsp;</p>
</el-form-item>
<el-form-item prop="freeGold" label="免费金币">
<el-form-item prop="freeGold" :label="$t('common_add.freeGold')">
<el-input v-model="recharge.freeGold" placeholder="0" style="width: 100px"/>
<p>&nbsp;</p>
</el-form-item>
<el-form-item label="充值金额" required>
<el-form-item :label="$t('common_add.rechargeAmount')" required>
<el-form-item prop="rateName" style="display: inline-block; margin-left:0;">
<el-select v-model="recharge.rateName" placeholder="货币名称" style="width: 100px">
<el-select v-model="recharge.rateName" :placeholder="$t('common_add.currencyName')" style="width: 100px">
<el-option v-for="item in rateName" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
</el-form-item>
@ -666,16 +669,16 @@ onMounted(() => {
</el-form-item>
</el-form-item>
<el-form-item prop="payModel" label="收款方式">
<el-select v-model="recharge.payModel" placeholder="请选择" style="width: 300px">
<el-form-item prop="payModel" :label="$t('common_add.payModel')">
<el-select v-model="recharge.payModel" :placeholder="$t('common_add.payModelPlaceholder')" style="width: 300px">
<el-option v-for="item in payModel" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
</el-form-item>
<el-form-item prop="payTime" label="交款时间">
<el-form-item prop="payTime" :label="$t('common_add.paymentTime')">
<!-- 修改 type 属性为 datetime 以支持时分秒选择 -->
<el-date-picker v-model="recharge.payTime" type="datetime" style="width: 300px"/>
</el-form-item>
<el-form-item prop="voucher" label="交款凭证" style="margin-bottom: 5px">
<el-form-item prop="voucher" :label="$t('common_add.paymentVoucher')" style="margin-bottom: 5px">
<el-upload :http-request="customUpload" class="avatar-uploader" :show-file-list="false"
:before-upload="beforeAvatarUpload" style="width: 100px; height: 115px">
<img v-if="imageUrl" :src="imageUrl" class="avatar" style="width: 100px; height: 115px"/>
@ -684,16 +687,16 @@ onMounted(() => {
</el-icon>
</el-upload>
<p style="margin-left: 10px; color: rgb(177, 176, 176)">
仅支持.jpg .png格式文件1MB
{{ $t('common_add.paymentVoucherPlaceholder') }}
</p>
</el-form-item>
<el-form-item prop="remark" label="备注">
<el-form-item prop="remark" :label="$t('common_add.remark')">
<el-input v-model="recharge.remark" style="width: 300px" :rows="4" maxlength="100" show-word-limit
type="textarea"/>
</el-form-item>
<el-button @click="deleteRecharge" style="margin-left: 220px;margin-top:20px" type="success">重置</el-button>
<el-button type="primary" style="margin-top:20px" :disabled="addDisabled" @click="addBefore"> 提交</el-button>
<el-button @click="deleteRecharge" style="margin-left: 220px;margin-top:20px" type="success">{{ $t('common.reset') }}</el-button>
<el-button type="primary" style="margin-top:20px" :disabled="addDisabled" @click="addBefore"> {{ $t('common.confirm') }}</el-button>
</el-form>
</div>
@ -701,28 +704,28 @@ onMounted(() => {
<!-- 客户信息栏 -->
<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-text size="large" style="margin-left: 20px">{{ $t('common_add_user.customerInfo') }}</el-text>
<!-- 第一行姓名 + 历史金币 -->
<el-row style="margin-top: 20px">
<el-col :span="9">
<el-form-item label="姓名">
<el-form-item :label="$t('common_add_user.name')">
<p>{{ user.name }}</p>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="当前金币总数" style="width: 500px">
<el-form-item :label="$t('common_add_user.currentGoldCoinTotal')" 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">(永久金币:{{
<span style="color: #b1b1b1; margin-left: 0px" v-if="user.nowPermanentGold !== undefined">({{ $t('common_add_user.permanentGold') }}:{{
user.nowPermanentGold
}};
免费金币:{{ user.nowFreeGold }};
任务金币:{{ user.nowTaskGold }})</span>
{{ $t('common_add_user.freeGold') }}:{{ user.nowFreeGold }};
{{ $t('common_add_user.taskGold') }}:{{ user.nowTaskGold }})</span>
</el-form-item>
</el-col>
</el-row>
@ -730,16 +733,16 @@ onMounted(() => {
<!-- 第二行精网号 + 当前金币独立行 -->
<el-row>
<el-col :span="9">
<el-form-item label="精网号">
<el-form-item :label="$t('common_add_user.jwcode')">
<p>{{ user.jwcode }}</p>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item label="消费次数">
<el-form-item :label="$t('common_add_user.consumptionTimes')">
<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>
<p style="font-size: small; color: #b1b1b1">({{ $t('common_add_user.onlyStatisticsDataAfter20250101') }})</p>
</el-form-item>
</el-col>
</el-row>
@ -759,7 +762,7 @@ onMounted(() => {
<!-- 第四行消费次数 + 所属门店 -->
<el-row>
<el-col :span="9">
<el-form-item label="所属门店">
<el-form-item :label="$t('common_add_user.store')">
<p>{{ user.market }}</p>
</el-form-item>
</el-col>
@ -770,39 +773,39 @@ onMounted(() => {
</div>
<el-dialog v-model="FirstRechargeDialogVisible" title="操作确认"
<el-dialog v-model="FirstRechargeDialogVisible" :title="$t('common_add.operationConfirm')"
:before-close="FirstRechargeDialogVisiblehandleClose"
:close-on-click-modal="false" width="400px">
<!-- 内容整体居中且收窄 -->
<div class="confirm-body">
<!-- 用户信息 -->
<div>
<div class="field-label">用户信息</div>
<div class="field-label">{{ $t('common_add.userInfo') }}</div>
<el-input :model-value="user.jwcode + (user.name ? '' + user.name + '' : '')" disabled/>
</div>
<!-- 活动名称 -->
<div class="field">
<div class="field-label">活动名称</div>
<div class="field-label">{{ $t('common_add.activity') }}</div>
<el-input v-model="recharge.activity" disabled/>
</div>
<!-- 金币信息同一行左右排列 -->
<el-row :gutter="20" class="coins-row">
<el-col :span="12">
<div class="field">
<div class="field-label">永久金币</div>
<div class="field-label">{{ $t('common_add.permanentGold') }}</div>
<el-input v-model="recharge.permanentGold" disabled/>
</div>
</el-col>
<el-col :span="12">
<div class="field">
<div class="field-label">免费金币</div>
<div class="field-label">{{ $t('common_add.freeGold') }}</div>
<el-input v-model="recharge.freeGold" disabled/>
</div>
</el-col>
</el-row>
<div class="field">
<div class="field-label">备注</div>
<div class="field-label">{{ $t('common_add.remark') }}</div>
<el-input v-model="recharge.remark" disabled/>
</div>
@ -812,37 +815,37 @@ onMounted(() => {
<!-- 底部按钮居中 -->
<template #footer>
<div class="dialog-footer-center">
<el-button @click="FirstRechargeDialogVisibleCancel"> </el-button>
<el-button type="primary" @click="FistRechargeDialogVisibleContinue">确认充值</el-button>
<el-button @click="FirstRechargeDialogVisibleCancel">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="FistRechargeDialogVisibleContinue">{{ $t('common.confirmRecharge') }}</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="RechargeDialogVisible" title="操作确认" :before-close="RechargeDialogVisiblehandleClose"
<el-dialog v-model="RechargeDialogVisible" :title="$t('common_add.operationConfirm')" :before-close="RechargeDialogVisiblehandleClose"
:close-on-click-modal="false" width="480px">
<!-- 内容整体居中且收窄 -->
<div class="confirm-body">
<!-- 用户信息 -->
<div>
<div class="field-label">用户信息</div>
<div class="field-label">{{ $t('common_add.userInfo') }}</div>
<el-input :model-value="user.jwcode + (user.name ? '' + user.name + '' : '')" disabled/>
</div>
<!-- 活动名称 -->
<div class="field">
<div class="field-label">活动名称</div>
<div class="field-label">{{ $t('common_add.activity') }}</div>
<el-input v-model="recharge.activity" disabled/>
</div>
<!-- 金币信息同一行左右排列 -->
<el-row :gutter="20" class="coins-row">
<el-col :span="12">
<div class="field">
<div class="field-label">永久金币</div>
<div class="field-label">{{ $t('common_add.permanentGold') }}</div>
<el-input v-model="recharge.permanentGold" disabled/>
</div>
</el-col>
<el-col :span="12">
<div class="field">
<div class="field-label">免费金币</div>
<div class="field-label">{{ $t('common_add.freeGold') }}</div>
<el-input v-model="recharge.freeGold" disabled/>
</div>
</el-col>
@ -852,17 +855,17 @@ onMounted(() => {
<el-icon :size="24" color="#FFD700">
<WarnTriangleFilled/>
</el-icon>
<p>重复充值风险提示</p>
<p>{{ $t('common_add.prompt') }}</p>
</div>
<!-- 记录 + 虚线分隔 -->
<div>
<el-divider border-style="dashed"/>
<p>检测到该用户近期有相似充值记录</p>
· {{ ReadCookiesTime }} 充值永久金币: {{ recharge.permanentGold }}
免费金币: {{ recharge.freeGold }}(操作人{{ adminData.adminName }})
<p>{{ $t('common_add.similarRechargeRecords') }}</p>
· {{ ReadCookiesTime }} {{ $t('common_add.rechargePermanentGold') }}: {{ recharge.permanentGold }}
{{ $t('common_add.freeGold') }}: {{ recharge.freeGold }}({{ $t('common_add.operator') }}{{ adminData.adminName }})
</div>
<div style="margin-top: 10px">
<p>是否继续操作</p>
<p>{{ $t('common_add.continueOperation') }}</p>
</div>
</div>
@ -870,8 +873,8 @@ onMounted(() => {
<!-- 底部按钮居中 -->
<template #footer>
<div class="dialog-footer-center">
<el-button @click="RechargeDialogVisibleCancel"> </el-button>
<el-button type="primary" @click="RechargeDialogVisibleContinue">确认充值</el-button>
<el-button @click="RechargeDialogVisibleCancel">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="RechargeDialogVisibleContinue">{{ $t('common.confirmRecharge') }}</el-button>
</div>
</template>
</el-dialog>

7
src/views/recharge/gold/coinRecharge.vue

@ -6,13 +6,13 @@
:class="{ 'active-btn': activeTab === 'coinRechargeDetail' }"
@click="navigateTo('coinRechargeDetail')"
v-if="hasDetail">
金币充值明细
{{ $t('recharge.coinRechargeDetail') }}
</el-button>
<el-button class="no-active-btn"
:class="{ 'active-btn': activeTab === 'addCoinRecharge' }"
@click="navigateTo('addCoinRecharge')"
v-if="hasAdd">
新增充值
{{ $t('recharge.addCoinRecharge') }}
</el-button>
</el-button-group>
</div>
@ -25,6 +25,9 @@ import {useRoute, useRouter} from 'vue-router';
import {storeToRefs} from "pinia";
import {useAdminStore} from "@/store/index.js";
import {hasMenuPermission, permissionMapping} from "@/utils/menuTreePermission.js";
//
import { useI18n } from 'vue-i18n';
const router = useRouter();
const route = useRoute();

121
src/views/recharge/gold/coinRechargeDetail.vue

@ -9,6 +9,9 @@ import { storeToRefs } from 'pinia'
import { useAdminStore } from '@/store/index.js'
const adminStore = useAdminStore()
const { flag } = storeToRefs(adminStore)
//
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
//
// const showEmployeeData = ref(false)
@ -229,7 +232,7 @@ const getActivity = async function () {
activity.value = result.data.map(item => ({ value: item, label: item }));
} else {
console.error('活动数据格式错误', result)
ElMessage.error('活动数据格式错误,请联系管理员')
ElMessage.error($t('elmessage.activityFormatError'))
}
console.log('activity', activity.value)
@ -293,11 +296,11 @@ const getPlatform = async () => {
platform.value = result.data.map(item => ({ value: item, label: item }));
} else {
console.error('充值方式格式错误', result)
ElMessage.error('充值方式格式错误,请联系管理员')
ElMessage.error($t('elmessage.rechargeFormatError'))
}
} catch (error) {
console.error('获取充值方式失败:', error);
ElMessage.error('获取充值方式失败,请稍后重试');
ElMessage.error($t('elmessage.getRechargeError'))
} finally {
isLoadingPlatform.value = false
}
@ -336,7 +339,7 @@ const get = async function (val) {
//
if (!numberRegex.test(rechargeUser.value.jwcode)) {
ElMessage.error('请检查精网号格式')
ElMessage.error($t('elmessage.checkJwcodeFormat'))
//
return
}
@ -509,13 +512,13 @@ const exportExcel = async function () {
try {
const res = await API({ url: '/export/exportRecharge', data: params })
if (res.code === 200) {
ElMessage.success('导出成功')
ElMessage.success($t('elmessage.exportSuccess'))
} else {
ElMessage.error(res.message || '导出失败,请稍后重试')
ElMessage.error(res.message || $t('elmessage.exportFailed'))
}
} catch (error) {
console.log('请求失败', error)
ElMessage.error('导出失败,请稍后重试')
ElMessage.error($t('elmessage.exportFailed'))
}
}
@ -542,11 +545,11 @@ const getExportList = async () => {
});
exportList.value = filteredData
} else {
ElMessage.error(result.msg || '获取导出列表失败')
ElMessage.error(result.msg || $t('elmessage.getExportListError'))
}
} catch (error) {
console.error('获取导出列表出错:', error)
ElMessage.error('获取导出列表失败,请稍后重试')
ElMessage.error($t('elmessage.getExportListError'))
} finally {
exportListLoading.value = false
}
@ -559,7 +562,7 @@ const downloadExportFile = (item) => {
link.download = item.fileName
link.click()
} else {
ElMessage.warning('文件还在导出中,请稍后再试')
ElMessage.warning($t('elmessage.exportingInProgress'))
}
}
//
@ -581,15 +584,15 @@ const getTagType = (state) => {
const getTagText = (state) => {
switch (state) {
case 0:
return '待执行';
return $t('elmessage.pendingExecution');
case 1:
return '执行中';
return $t('elmessage.executing');
case 2:
return '执行完成';
return $t('elmessage.executed');
case 3:
return '执行出错';
return $t('elmessage.errorExecution');
default:
return '未知状态';
return $t('elmessage.unknownStatus');
}
}
@ -601,23 +604,23 @@ const getTagText = (state) => {
<el-col style="margin-bottom: 1vh">
<div class="select">
<div class="selectRow">
<el-text class="text" size="large">精网号</el-text>
<el-input class="selectContent" v-model="rechargeUser.jwcode" placeholder="请输入精网号" clearable />
<el-text class="text" size="large">{{ $t('common.jwcode') }}</el-text>
<el-input class="selectContent" v-model="rechargeUser.jwcode" :placeholder="$t('common.jwcodePlaceholder')" clearable />
</div>
<div class="selectRow">
<el-text class="text" size="large">活动名称</el-text>
<el-select class="selectContent" v-model="rechargeUser.activity" placeholder="请选择活动名称" clearable>
<el-text class="text" size="large">{{ $t('common.activityName') }}</el-text>
<el-select class="selectContent" v-model="rechargeUser.activity" :placeholder="$t('common.activityNamePlaceholder')" clearable>
<el-option v-for="item in activity" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div class="selectRow" style="width: 15vw;">
<el-text class="text" size="large">所属地区</el-text>
<el-cascader class="selectContent" v-model="selectedMarketPath" :options="market" placeholder="请选择所属地区"
<el-text class="text" size="large">{{ $t('common.market') }}</el-text>
<el-cascader class="selectContent" v-model="selectedMarketPath" :options="market" :placeholder="$t('common.marketPlaceholder')"
clearable @change="handleMarketChange" />
</div>
<div class="selectRow" style="width: 15vw;">
<el-text class="text" size="large">充值平台</el-text>
<el-select class="selectContent" v-model="rechargeUser.payPlatform" placeholder="请选择充值平台" clearable>
<el-text class="text" size="large">{{ $t('common.rechargePlatform') }}</el-text>
<el-select class="selectContent" v-model="rechargeUser.payPlatform" :placeholder="$t('common.rechargePlatformPlaceholder')" clearable>
<el-option v-for="item in platform" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
@ -627,9 +630,9 @@ const getTagText = (state) => {
<el-col>
<div class="select">
<div class="selectRow" style="width: 36vw;">
<el-text class="text" size="large">充值时间</el-text>
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" range-separator=""
start-placeholder="起始时间" end-placeholder="结束时间" style="margin-right:1vw;width:25vw"
<el-text class="text" size="large">{{ $t('common.rechargeTime') }}</el-text>
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" :range-separator="$t('common.to')"
:start-placeholder="$t('common.startTime')" :end-placeholder="$t('common.endTime')" style="margin-right:1vw;width:25vw"
@change="handleDatePickerChange" :default-time="defaultTime" :disabled-date="disabledDate" />
<div v-if="false">
<el-button @click="getToday()" style="margin-left: 1vw"
@ -646,10 +649,10 @@ const getTagText = (state) => {
</div>
</div>
<div class="selectRow" style="justify-content: flex-start;">
<el-button type="primary" @click="search()">查询</el-button>
<el-button type="primary" @click="exportExcel()">导出Excel</el-button>
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()">{{ $t('common.search') }}</el-button>
<el-button type="primary" @click="exportExcel()">{{ $t('common.exportExcel') }}</el-button>
<el-button type="primary" @click="openExportList">{{ $t('common.viewExportList') }}</el-button>
<el-button type="success" @click="reset()">{{ $t('common.reset') }}</el-button>
</div>
</div>
@ -658,41 +661,41 @@ const getTagText = (state) => {
<el-card class="card2">
<div class="goldStatistics">
充值新币{{ format3(permanentGolds) }}新币&nbsp;&nbsp;&nbsp;&nbsp;
总金币数{{ format3(permanentGolds + freeGolds) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(permanentGolds) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
免费金币{{ format3(freeGolds) }}金币
{{ $t('common.rechargeSGD') }}{{ format3(permanentGolds) }} {{ $t('common.SGD') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('common.totalGoldCoin') }}{{ format3(permanentGolds + freeGolds) }} {{ $t('common.goldCoin') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('common.permanentGold') }}{{ format3(permanentGolds) }} {{ $t('common.goldCoin') }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('common.freeGold') }}{{ format3(freeGolds) }} {{ $t('common.goldCoin') }}
</div>
<!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 66vh;">
<el-table :data="tableData" height="66vh" @sort-change="handleSortChange">
<el-table-column type="index" label="序号" width="80px" fixed="left">
<el-table-column type="index" :label="$t('common_list.id')" width="80px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column fixed="left" prop="name" label="姓名" width="150px" />
<el-table-column fixed="left" prop="jwcode" label="精网号" width="110px" />
<el-table-column prop="market" label="所属地区" width="100px" />
<el-table-column prop="activity" label="活动名称" width="110px" show-overflow-tooltip />
<el-table-column prop="rateName" label="货币名称" width="110px" />
<el-table-column prop="money" sortable="custom" label="充值金额" width="110px" />
<el-table-column prop="permanentGold" label="永久金币" sortable="custom" width="110px" />
<el-table-column prop="freeGold" label="免费金币" sortable="custom" width="110px" />
<el-table-column prop="payPlatform" label="充值平台" width="110px" />
<el-table-column prop="payModel" label="支付方式" width="100px" />
<el-table-column prop="remark" label="备注" width="150px" show-overflow-tooltip />
<el-table-column prop="isRefund" label="订单状态" width="200px" show-overflow-tooltip>
<el-table-column fixed="left" prop="name" :label="$t('common_list.name')" width="150px" />
<el-table-column fixed="left" prop="jwcode" :label="$t('common_list.jwcode')" width="110px" />
<el-table-column prop="market" :label="$t('common_list.market')" width="100px" />
<el-table-column prop="activity" :label="$t('common_list.activity')" width="110px" show-overflow-tooltip />
<el-table-column prop="rateName" :label="$t('common_list.rateName')" width="110px" />
<el-table-column prop="money" sortable="custom" :label="$t('common_list.rechargeAmount')" width="110px" />
<el-table-column prop="permanentGold" :label="$t('common_list.permanentGold')" sortable="custom" width="110px" />
<el-table-column prop="freeGold" :label="$t('common_list.freeGold')" sortable="custom" width="110px" />
<el-table-column prop="payPlatform" :label="$t('common_list.rechargePlatform')" width="110px" />
<el-table-column prop="payModel" :label="$t('common_list.payModel')" width="100px" />
<el-table-column prop="remark" :label="$t('common_list.remark')" width="150px" show-overflow-tooltip />
<el-table-column prop="isRefund" :label="$t('common_list.orderStatus')" width="200px" show-overflow-tooltip>
<template #default="scope">
<span v-if="scope.row.isRefund == 0">正常</span>
<span v-else-if="scope.row.isRefund == 1">已退款</span>
<span v-else>未知状态</span>
<span v-if="scope.row.isRefund == 0">{{ $t('recharge.normal') }}</span>
<span v-else-if="scope.row.isRefund == 1">{{ $t('recharge.refunded') }}</span>
<span v-else>{{ $t('recharge.unknown') }}</span>
</template>
</el-table-column>
<el-table-column prop="adminName" label="提交人" width="100px" />
<el-table-column prop="auditTime" sortable label="充值时间" width="200px">
<el-table-column prop="adminName" :label="$t('common_list.submitter')" width="100px" />
<el-table-column prop="auditTime" sortable :label="$t('common_list.rechargeTime')" width="200px">
<template #default="scope">
{{ moment(scope.row.auditTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
@ -709,33 +712,33 @@ const getTagText = (state) => {
</el-card>
<!-- 导出弹窗 -->
<el-dialog v-model="exportListVisible" title="导出列表" width="80%">
<el-dialog v-model="exportListVisible" :title="$t('common_export.exportList')" width="80%">
<el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
<el-table-column prop="fileName" label="文件名" />
<el-table-column prop="state" label="状态">
<el-table-column prop="fileName" :label="$t('common_export.fileName')" />
<el-table-column prop="state" :label="$t('common_export.status')">
<template #default="scope">
<el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
{{ getTagText(scope.row.state) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间">
<el-table-column prop="createTime" :label="$t('common_export.createTime')">
<template #default="scope">
{{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作">
<el-table-column :label="$t('common_export.operation')">
<template #default="scope">
<el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
:disabled="scope.row.state !== 2">
下载
{{ $t('common_export.download') }}
</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button text @click="exportListVisible = false">关闭</el-button>
<el-button text @click="exportListVisible = false">{{ $t('common_export.close') }}</el-button>
</div>
</template>
</el-dialog>

138
src/views/refund/gold/addCoinRefund.vue

@ -9,6 +9,10 @@ import { e } from 'mathjs';
const adminStore = useAdminStore();
const { adminData, menuTree } = storeToRefs(adminStore);
//
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const tableData = ref([])
const pagination = ref({
@ -60,7 +64,7 @@ const cancel = function () {
const getRefund = async function () {
if (!addRefund.value.jwcode) {
ElMessage.error('请输入精网号')
ElMessage.error(t('elmessage.checkJwCode'))
return
}
addRefund.value.orderCode = ''
@ -69,7 +73,7 @@ const getRefund = async function () {
addRefund.value.freeGold = ''
addRefund.value.taskGold = ''
let type = null
if (addRefund.value.refundType === '商品退款') {
if (addRefund.value.refundType === t('refund.refundTypeOptions.商品退款')) {
type = 1
} else {
type = 0
@ -100,11 +104,11 @@ const getRefund = async function () {
}))
console.log("看看订单号们", orderCodes.value)
} else {
ElMessage.info("未查询到相关订单")
ElMessage.info(t('elmessage.noOrder'))
}
} catch (error) {
console.log('goldDetail有错误', error)
ElMessage.error('请求失败')
ElMessage.error(t('elmessage.requestFailed'))
tableData.value = []
pagination.value.total = 0
}
@ -113,11 +117,11 @@ const getRefund = async function () {
const add = async function () {
//
if (!canAdd.value) {
ElMessage.error('无此权限')
ElMessage.error(t('elmessage.noPermission'))
return
}
try {
if (addRefund.value.refundType === '商品退款') {
if (addRefund.value.refundType === t('refund.refundTypeOptions.商品退款')) {
addRefund.value.type = 1
} else {
addRefund.value.type = 0
@ -144,7 +148,7 @@ const add = async function () {
return
}
console.log('请求成功', result)
ElMessage.success('添加成功')
ElMessage.success(t('elmessage.addSuccess'))
//
cancel()
} catch (error) {
@ -161,7 +165,7 @@ const addDisabled = ref(false)
const addBefore = () => {
Ref.value.validate(async (valid) => {
if (valid) {
ElMessageBox.confirm('确认退款?')
ElMessageBox.confirm(t('elmessage.confirmRefund'))
.then(() => {
add()
})
@ -172,7 +176,7 @@ const addBefore = () => {
//
ElMessage({
type: 'error',
message: '请检查输入内容'
message: t('elmessage.checkInputContent')
})
}
})
@ -182,32 +186,32 @@ const addBefore = () => {
const Ref = ref(null)
const validateJwCode = (rule, value, callback) => {
if (!value) {
callback(new Error('精网号不能为空'));
callback(new Error(t('elmessage.noEmptyJwcode')));
return;
}
if (/[^0-9]/.test(value)) {
callback(new Error('精网号只能包含数字'));
callback(new Error(t('elmessage.limitDigitJwcode')));
return;
}
callback();
};
const rules = reactive({
jwcode: [{ required: true, validator: validateJwCode, trigger: 'blur' }],
refundType: [{ required: true, message: '请选择退款类型', trigger: 'blur' }],
goodsName: [{ required: false, message: '请选择退款商品', trigger: 'blur' }],
refundType: [{ required: true, message: t('elmessage.checkRefundType'), trigger: 'blur' }],
goodsName: [{ required: false, message: t('elmessage.checkRefundGoods'), trigger: 'blur' }],
//
orderCode: [{ required: true, message: '请输入订单号', trigger: 'blur' }],
taskGold: [{ required: true, message: '请输入任务金币', trigger: 'blur' }],
freeGold: [{ required: true, message: '请输入免费金币', trigger: 'blur' }],
orderCode: [{ required: true, message: t('elmessage.checkOrderNo'), trigger: 'blur' }],
taskGold: [{ required: true, message: t('elmessage.checkTaskGold'), trigger: 'blur' }],
freeGold: [{ required: true, message: t('elmessage.checkFreeGold'), trigger: 'blur' }],
permanentGold: [
{ required: true, message: '请输入永久金币', trigger: 'blur' }
{ required: true, message: t('elmessage.checkPermanentGold'), trigger: 'blur' }
],
sumGold: [
{ required: true, message: '请选择付款方式', trigger: 'blur' },
{ required: true, message: t('elmessage.checkPayModel'), trigger: 'blur' },
{
validator: (rule, value) => {
if (value === 0) {
return Promise.reject(new Error('总金币不能为0'))
return Promise.reject(new Error(t('elmessage.noTotalGoldZero')))
}
return Promise.resolve()
},
@ -223,7 +227,7 @@ const getUser = async function (jwcode) {
trimJwCode();
//
if (!jwcode) {
ElMessage.warning('精网号不能为空');
ElMessage.warning(t('elmessage.noEmptyJwcode'));
return;
}
@ -248,7 +252,7 @@ const getUser = async function (jwcode) {
if (result.code === 0) {
ElMessage.error(result.msg);
} else if (result.data === null) {
ElMessage.error("用户不存在");
ElMessage.error(t('elmessage.noUser'));
} else {
// 100
const processedData = {
@ -267,15 +271,15 @@ const getUser = async function (jwcode) {
}
} catch (error) {
console.log("请求失败", error);
ElMessage.error("精网号错误");
ElMessage.error(t('elmessage.jwcodeError'));
}
}
// 退退
const refundType = ref([
{ value: '商品退款', label: '商品退款' },
{ value: '金币退款', label: '金币退款' }
{ value: '商品退款', label: t('refund.refundTypeOptions.商品退款') },
{ value: '金币退款', label: t('refund.refundTypeOptions.金币退款') }
])
//
@ -292,7 +296,7 @@ const handleOrderChange = (orderCode) => {
const order = tableData.value.find(item => item.orderCode === orderCode)
if (order) {
addRefund.value.goodsName = order.goodsName
if (addRefund.value.refundType === '金币退款') {
if (addRefund.value.refundType === t('refund.refundTypeOptions.金币退款')) {
selectedGoodsGold.value = {
permanentGold: Number(order.permanentGold) || 0,
freeGold: Number(order.freeGold) || 0,
@ -391,13 +395,13 @@ const handleGoldInput = (type, value) => {
//
const correctedValue = maxValue.toFixed(2);
addRefund.value[type] = correctedValue;
ElMessage.warning('所填金额大于该类金币余额');
ElMessage.warning(t('elmessage.limitBalance'));
}
if (inputValue < 0) {
// 0
addRefund.value[type] = '0';
ElMessage.warning('不能输入负数');
ElMessage.warning(t('elmessage.noNegativeNumber'));
}
}
@ -436,73 +440,73 @@ onMounted(() =>{
<div class="left">
<el-form :model="addRefund" ref="Ref" :rules="rules" label-width="auto" label-position="right"
style="min-width: 420px" class="add-form">
<el-form-item prop="jwcode" label="精网号">
<el-form-item prop="jwcode" :label="$t('common_add.jwcode')">
<el-input v-model="addRefund.jwcode" style="width: 220px" />
<el-button type="primary" @click="getUser(addRefund.jwcode)" style="margin-left: 20px">查询
<el-button type="primary" @click="getUser(addRefund.jwcode)" style="margin-left: 20px">{{ $t('common.search') }}
</el-button>
</el-form-item>
<el-form-item prop="refundType" label="退款类型">
<el-select v-model="addRefund.refundType" placeholder="请选择" style="width: 220px"
<el-form-item prop="refundType" :label="$t('common_add.refundType')">
<el-select v-model="addRefund.refundType" :placeholder="$t('common_add.refundTypePlaceholder')" style="width: 220px"
@change="getRefund(addRefund.jwcode)">
<el-option v-for="item in refundType" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item prop="orderCode" label="订单号">
<el-select v-model="addRefund.orderCode" placeholder="请选择订单号" style="width: 220px;" clearable filterable
<el-form-item prop="orderCode" :label="$t('common_add.orderNo')">
<el-select v-model="addRefund.orderCode" :placeholder="$t('common_add.orderNoPlaceholder')" style="width: 220px;" clearable filterable
@change="handleOrderChange">
<el-option v-for="(item, index) in orderCodes" :key="index" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item prop="goodsName" label="商品名">
<el-form-item prop="goodsName" :label="$t('common_add.goodsName')">
<el-input v-model="addRefund.goodsName" style="width: 220px" disabled />
</el-form-item>
<el-form-item prop="refundModel" label="退款方式:">
<el-form-item prop="refundModel" :label="$t('common_add.refundModel')">
<el-radio-group v-model="addRefund.refundModel" @change="handleRefundModelChange">
<el-radio :value="0">全部退款</el-radio>
<el-radio :value="1">部分退款</el-radio>
<el-radio :value="0">{{ $t('common_add.refundModelAll') }}</el-radio>
<el-radio :value="1">{{ $t('common_add.refundModelPart') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="permanentGold" label="永久金币">
<el-form-item prop="permanentGold" :label="$t('common_add.permanentGold')">
<el-input v-model="addRefund.permanentGold" style="width: 220px" :disabled="addRefund.refundModel === 0"
@input="handlePermanentGoldInput($event)" type="number">
</el-input>&nbsp;&nbsp;
</el-input>&nbsp;&nbsp;{{ $t('common.') }}
<template>
</template>
</el-form-item>
<el-form-item prop="freeGold" label="免费金币">
<el-form-item prop="freeGold" :label="$t('common_add.freeGold')">
<el-input v-model="addRefund.freeGold" style="float: left; width: 220px"
:disabled="addRefund.refundModel === 0" @input="handleFreeGoldInput($event)" type="number" />
&nbsp;&nbsp;
&nbsp;&nbsp;{{ $t('common.') }}
</el-form-item>
<div>
<el-form-item prop="taskGold" label="任务金币">
<el-form-item prop="taskGold" :label="$t('common_add.taskGold')">
<el-input v-model="addRefund.taskGold" style="float: left; width: 220px"
:disabled="addRefund.refundModel === 0" @input="handleTaskGoldInput($event)" type="number" />
&nbsp;&nbsp;
&nbsp;&nbsp;{{ $t('common.') }}
</el-form-item>
</div>
<div>
<el-form-item prop="sumGold" label="退款金币总数">
<el-form-item prop="sumGold" :label="$t('common_add.refundGoldCoin')">
<el-input disabled v-model="addRefund.sumGold" style="width: 220px">
</el-input>
</el-form-item>
</div>
<div>
<el-form-item prop="remark" label="备注">
<el-form-item prop="remark" :label="$t('common_add.remark')">
<el-input v-model="addRefund.remark" style="width: 220px" :rows="3" maxlength="100" show-word-limit
type="textarea" />
</el-form-item>
</div>
<el-button type="success" @click="cancel()" style="margin-left: 200px">重置</el-button>
<el-button type="primary" :disabled="addDisabled" @click="addBefore" v-if="canAdd"> 提交</el-button>
<el-button type="success" @click="cancel()" style="margin-left: 200px">{{ $t('common.reset') }}</el-button>
<el-button type="primary" :disabled="addDisabled" @click="addBefore" v-if="canAdd"> {{ $t('common.submit') }}</el-button>
</el-form>
</div>
</div>
@ -512,13 +516,13 @@ onMounted(() =>{
<!-- 客户信息栏 -->
<el-card v-if="user.jwcode" class="customer-info">
<el-form :model="user" label-width="auto" label-position="left">
<span style="margin-left: 30%;font-size: larger;">客户信息</span>
<span style="margin-left: 30%;font-size: larger;">{{ $t('common_add_user.customerInfo') }}</span>
<el-row style="margin-top: 1vh;">
<div class="line">
<span style="width:5vw;">姓名</span>
<span style="width:5vw;">{{ $t('common_add_user.name') }}</span>
<span style="width:10vw;">{{ user.name }}</span>
<span style="width:10vw;">当前金币总数</span>
<span style="width:10vw;">{{ $t('common_add_user.currentGoldCoinTotal') }}</span>
<span style="color: #2fa1ff;width: 25vw;" v-if="user.nowSumGold !== undefined">{{
user.nowSumGold
}}</span>
@ -526,30 +530,30 @@ onMounted(() =>{
</el-row>
<el-row style="height: 3vh;width: 100%;">
<span style="height:3vh;color: #b1b1b1;font-size: small;margin-left:50%;"
v-if="user.nowPermanentGold !== undefined">(永久金币:{{
v-if="user.nowPermanentGold !== undefined">({{ $t('common_add_user.permanentGold') }}:{{
user.nowPermanentGold
}};
免费金币:{{ user.nowFreeGold }};
任务金币:{{ user.nowTaskGold }})</span>
{{ $t('common_add_user.freeGold') }}:{{ user.nowFreeGold }};
{{ $t('common_add_user.taskGold') }}:{{ user.nowTaskGold }})</span>
</el-row>
<el-row>
<!-- 第二行精网号 + 消费次数 -->
<div class="line">
<span style="width:5vw;">精网号</span>
<span style="width:5vw;">{{ $t('common_add_user.jwcode') }}</span>
<span style="width: 10vw;">{{ user.jwcode }}</span>
<span style="width:10vw;">消费次数</span>
<span style="width:10vw;">{{ $t('common_add_user.consumptionTimes') }}</span>
<span style="width: 10vw;color: #2fa1ff;">{{ user.consumeNum }}</span>
</div>
</el-row>
<el-row>
<span style="height:3vh;color: #b1b1b1;font-size: small;margin-left:50%;">(仅统计2025-01-01后的数据)</span>
<span style="height:3vh;color: #b1b1b1;font-size: small;margin-left:50%;">({{ $t('common_add_user.onlyStatisticsDataAfter20250101') }}2025-01-01)</span>
</el-row>
<!-- 第四行所属门店 -->
<el-row>
<div class="line">
<span style="width:5vw;">所属门店</span>
<span style="width:5vw;">{{ $t('common_add_user.store') }}</span>
<span style="width: 10vw;">{{ user.market }}</span>
</div>
</el-row>
@ -560,38 +564,38 @@ onMounted(() =>{
<div>
<el-card class="card" v-if="tableData.length > 0">
<el-table :data="tableData" style="height:43vh;width:50vw">
<el-table-column type="index" label="序号" width="80">
<el-table-column type="index" :label="$t('refund.id')" width="80">
<template #default="scope">
<span>{{
scope.$index + 1 + (pagination.pageNum - 1) * pagination.pageSize
}}</span>
</template>
</el-table-column>
<el-table-column prop="type" label="类型" width="100">
<el-table-column prop="type" :label="$t('refund.type')" width="100">
<template #default="{ row }">
{{ row.type === 0 ? '充值' : '消费' }}
{{ row.type === 0 ? $t('refund.recharge') : $t('refund.consume') }}
</template>
</el-table-column>
<el-table-column prop="goodsName" label="商品名称" width="120" show-overflow-tooltip />
<el-table-column prop="orderCode" label="订单号" width="200px" show-overflow-tooltip />
<el-table-column prop="permanentGold" label="永久金币" width="120">
<el-table-column prop="goodsName" :label="$t('refund.productName')" width="120" show-overflow-tooltip />
<el-table-column prop="orderCode" :label="$t('refund.orderCode')" width="200px" show-overflow-tooltip />
<el-table-column prop="permanentGold" :label="$t('refund.permanentGold')" width="120">
<template #default="{ row }">
{{ row.permanentGold }}
</template>
</el-table-column>
<el-table-column prop="freeGold" label="免费金币" width="120">
<el-table-column prop="freeGold" :label="$t('refund.freeGold')" width="120">
<template #default="{ row }">
{{ row.freeGold }}
</template>
</el-table-column>
<el-table-column prop="taskGold" label="任务金币" width="120">
<el-table-column prop="taskGold" :label="$t('refund.taskGold')" width="120">
<template #default="{ row }">
{{ row.taskGold }}
</template>
</el-table-column>
<el-table-column prop="isRefund" label="允许退款" width="120">
<el-table-column prop="isRefund" :label="$t('refund.isRefund')" width="120">
<template #default="{ row }">
{{ row.isRefund === 1 ? '否' : '是' }}
{{ row.isRefund === 1 ? $t('refund.no') : $t('refund.yes') }}
</template>
</el-table-column>
</el-table>

5
src/views/refund/gold/coinRefund.vue

@ -8,7 +8,7 @@
@click="navigateTo('coinRefundDetail')"
:disabled="!hasDetail"
v-if="hasDetail">
金币退款明细
{{ $t('refund.coinRefundDetail') }}
</el-button>
<!-- 切换后状态显示 primary 样式否则是默认样式 -->
<el-button
@ -17,7 +17,7 @@
@click="navigateTo('addCoinRefund')"
:disabled="!hasAdd"
v-if="hasAdd">
新增退款
{{ $t('refund.addCoinRefund') }}
</el-button>
</el-button-group>
<!-- 渲染子路由组件 -->
@ -33,6 +33,7 @@ import {useRoute, useRouter} from 'vue-router';
import {storeToRefs} from "pinia";
import {useAdminStore} from "@/store/index.js";
import {hasMenuPermission, permissionMapping} from "@/utils/menuTreePermission.js";
import { useI18n } from 'vue-i18n';
const router = useRouter();
const route = useRoute();

114
src/views/refund/gold/coinRefundDetail.vue

@ -10,6 +10,9 @@ import { useAdminStore } from "@/store/index.js";
import { storeToRefs } from "pinia";
import { findMenuById, permissionMapping } from "@/utils/menuTreePermission.js"
import dayjs from "dayjs";
//
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const adminStore = useAdminStore();
const { adminData, menuTree, flag } = storeToRefs(adminStore);
@ -49,7 +52,7 @@ const trimJwCode = () => {
if (!isNaN(numeric)) {
refundUser.value.jwcode = numeric;
} else {
ElMessage.error("精网号格式不正确,请输入数字");
ElMessage.error(t("elmessage.limitDigitJwcode"));
}
}
}
@ -112,7 +115,7 @@ const getRefundTypes = async function () {
refundType.value = result.data.map(item => ({ value: item, label: item }));
} else {
console.error('退款类型数据格式错误', result)
ElMessage.error('退款类型数据格式错误,请联系管理员')
ElMessage.error(t("elmessage.refundTypeError"))
}
console.log('退款类型', refundType.value)
} catch (error) {
@ -125,7 +128,7 @@ const getRefundTypes = async function () {
const getSelectBy = async function (val) {
if (!canLook.value) {
console.log('无此权限', canLook.value)
ElMessage.error('无此权限')
ElMessage.error(t("elmessage.noPermission"))
return
}
try {
@ -159,7 +162,7 @@ const getSelectBy = async function (val) {
//
if (!numberRegex.test(refundUser.value.jwcode)) {
ElMessage.error('请检查精网号格式')
ElMessage.error(t("elmessage.checkJwcodeFormat"))
//
return
}
@ -378,13 +381,13 @@ const exportExcel = async function () {
try {
const res = await API({ url: '/export/exportRefund', data: params })
if (res.code === 200) {
ElMessage.success('导出成功')
ElMessage.success(t("elmessage.exportSuccess"))
} else {
ElMessage.error(res.message || '导出失败,请稍后重试')
ElMessage.error(res.message || t("elmessage.exportFailed"))
}
} catch (error) {
console.log('请求失败', error)
ElMessage.error('导出失败,请稍后重试')
ElMessage.error(t("elmessage.exportFailed"))
}
}
@ -411,11 +414,11 @@ const getExportList = async () => {
});
exportList.value = filteredData
} else {
ElMessage.error(result.msg || '获取导出列表失败')
ElMessage.error(result.msg || t("elmessage.getExportListError"))
}
} catch (error) {
console.error('获取导出列表出错:', error)
ElMessage.error('获取导出列表失败,请稍后重试')
ElMessage.error(t("elmessage.getExportListFailed"))
} finally {
exportListLoading.value = false
}
@ -428,7 +431,7 @@ const downloadExportFile = (item) => {
link.download = item.fileName
link.click()
} else {
ElMessage.warning('文件还在导出中,请稍后再试')
ElMessage.warning(t("elmessage.exportingInProgress"))
}
}
//
@ -515,25 +518,25 @@ const getMarket = async function () {
<el-col style="margin-bottom: 1vh;">
<div class="select">
<div class="selectRow">
<el-text class="text" size="large">精网号</el-text>
<el-input class="selectContent" v-model="refundUser.jwcode" placeholder="请输入精网号" style="width: 10vw;"
<el-text class="text" size="large">{{ $t('common.jwcode') }}</el-text>
<el-input class="selectContent" v-model="refundUser.jwcode" :placeholder="$t('common.jwcodePlaceholder')" style="width: 10vw;"
clearable />
</div>
<div class="selectRow">
<el-text class="text" size="large">商品名称</el-text>
<el-select class="selectContent" v-model="refundUser.goodsName" placeholder="请选择商品名称" style="width: 10vw;"
<el-text class="text" size="large">{{ $t('common.goodsName') }}</el-text>
<el-select class="selectContent" v-model="refundUser.goodsName" :placeholder="$t('common.goodsNamePlaceholder')" style="width: 10vw;"
clearable filterable>
<el-option v-for="item in goods" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div class="selectRow">
<el-text class="text" size="large">所属地区</el-text>
<el-cascader class="selectContent" v-model="selectedMarketPath" :options="market" placeholder="请选择所属地区"
<el-text class="text" size="large">{{ $t('common.market') }}</el-text>
<el-cascader class="selectContent" v-model="selectedMarketPath" :options="market" :placeholder="$t('common.marketPlaceholder')"
clearable style="width:10vw" @change="handleMarketChange" />
</div>
<div class="selectRow" style="width: 12vw;">
<el-text size="large">退款类型</el-text>
<el-select class="selectContent" v-model="refundUser.refundType" placeholder="请选择退款类型" style="width: 10vw"
<el-text size="large">{{ $t('common.refundType') }}</el-text>
<el-select class="selectContent" v-model="refundUser.refundType" :placeholder="$t('common.refundTypePlaceholder')" style="width: 10vw"
clearable>
<el-option v-for="item in refundType" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
@ -544,27 +547,28 @@ const getMarket = async function () {
<el-col>
<div class="select">
<div class="selectRow" style="width: 35vw">
<el-text class="text" size="large">退款时间</el-text>
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" range-separator=""
start-placeholder="起始时间" end-placeholder="结束时间" style="width: 20vw;" @change="handleDatePickerChange"
<el-text class="text" size="large">{{ $t('common.refundTime') }}</el-text>
<el-date-picker class="selectContent" v-model="getTime" type="datetimerange" :range-separator="$t('common.to')"
:start-placeholder="$t('common.startTime')" :end-placeholder="$t('common.endTime')" style="width: 20vw;" @change="handleDatePickerChange"
:default-time="defaultTime" :disabled-date="disabledDate" />
<el-button @click="getToday()" style="margin-left: 0.3vw"
:type="activeTimeRange === 'today' ? 'primary' : ''">
{{ $t('common.today') }}
</el-button>
<el-button @click="getYesterday()" style="margin-left: 0.3vw"
:type="activeTimeRange === 'yesterday' ? 'primary' : ''">
:type="activeTimeRange === 'yesterday' ? 'primary' : ''">
{{ $t('common.yesterday') }}
</el-button>
<el-button @click="get7Days()" style="margin-left: 0.3vw"
:type="activeTimeRange === '7days' ? 'primary' : ''">
近7天
{{ $t('common.last7Days') }}
</el-button>
</div>
<div class="selectRow" style="justify-content: flex-start;">
<el-button type="primary" @click="search()" v-if="canLook">查询</el-button>
<el-button type="primary" @click="exportExcel">导出Excel</el-button>
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
<el-button type="success" @click="reset()">重置</el-button>
<el-button type="primary" @click="search()" v-if="canLook">{{ $t('common.search') }}</el-button>
<el-button type="primary" @click="exportExcel">{{ $t('common.exportExcel') }}</el-button>
<el-button type="primary" @click="openExportList">{{ $t('common.viewExportList') }}</el-button>
<el-button type="success" @click="reset()">{{ $t('common.reset') }}</el-button>
</div>
</div>
</el-col>
@ -572,16 +576,16 @@ const getMarket = async function () {
<el-card class="card2">
<div class="goldStatistics">
退款金币总数{{ format3(Math.abs(sumGolds).toFixed(2)) }}&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(Math.abs(permanentGolds).toFixed(2)) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金币{{ format3(Math.abs(freeGolds).toFixed(2)) }}&nbsp;&nbsp;&nbsp;&nbsp;
任务金币{{ format3(Math.abs(taskGolds).toFixed(2)) }}
{{ $t('common.refundGoldCoin') }}{{ format3(Math.abs(sumGolds).toFixed(2)) }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('common.permanentGold') }}{{ format3(Math.abs(permanentGolds).toFixed(2)) }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('common.freeGold') }}{{ format3(Math.abs(freeGolds).toFixed(2)) }}&nbsp;&nbsp;&nbsp;&nbsp;
{{ $t('common.taskGold') }}{{ format3(Math.abs(taskGolds).toFixed(2)) }}
</div>
<!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 65vh; ">
<el-table :data="tableData" style="height: 65vh" @sort-change="handleSortChange"
:row-style="{ height: '50px' }">
<el-table-column type="index" label="序号" width="80px" fixed="left">
<el-table-column type="index" :label="$t('common_list.id')" width="80px" fixed="left">
<template #default="scope">
<span>{{
scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
@ -589,24 +593,24 @@ const getMarket = async function () {
</template>
</el-table-column>
<el-table-column prop="name" label="姓名" fixed="left" width="130px" show-overflow-tooltip />
<el-table-column prop="jwcode" label="精网号" fixed="left" width="110px" />
<el-table-column prop="market" label="所属地区" width="110px" />
<el-table-column prop="orderCode" label="订单号" width="260px" show-overflow-tooltip />
<el-table-column prop="goodsName" label="商品名称" width="110px" show-overflow-tooltip />
<el-table-column prop="refundType" label="退款类型" width="100px" />
<el-table-column prop="refundModel" label="退款方式" width="110px">
<el-table-column prop="name" :label="$t('common_list.name')" fixed="left" width="130px" show-overflow-tooltip />
<el-table-column prop="jwcode" :label="$t('common_list.jwcode')" fixed="left" width="110px" />
<el-table-column prop="market" :label="$t('common_list.market')" width="110px" />
<el-table-column prop="orderCode" :label="$t('common_list.orderNo')" width="260px" show-overflow-tooltip />
<el-table-column prop="goodsName" :label="$t('common_list.goodsName')" width="110px" show-overflow-tooltip />
<el-table-column prop="refundType" :label="$t('common_list.refundType')" width="100px" />
<el-table-column prop="refundModel" :label="$t('common_list.refundModel')" width="110px">
<template #default="scope">
{{ scope.row.refundModel === 0 ? '全部退款' : scope.row.refundModel === 1 ? '部分退款' : '' }}
{{ scope.row.refundModel === 0 ? $t('common_list.refundModelAll') : scope.row.refundModel === 1 ? $t('common_list.refundModelPart') : '' }}
</template>
</el-table-column>
<el-table-column prop="sumGold" label="退款金币总数" width="150px" sortable="custom" />
<el-table-column prop="permanentGold" label="永久金币" width="110px" sortable="custom" />
<el-table-column prop="freeGold" sortable="custom" label="免费金币" width="110px" />
<el-table-column prop="taskGold" sortable="custom" label="任务金币" width="110px" />
<el-table-column prop="remark" label="退款原因" width="160px" show-overflow-tooltip />
<el-table-column prop="adminName" label="提交人" width="100px" />
<el-table-column prop="auditTime" sortable="custom" label="退款时间" width="180px">
<el-table-column prop="sumGold" :label="$t('common_list.refundGoldCoin')" width="150px" sortable="custom" />
<el-table-column prop="permanentGold" :label="$t('common_list.permanentGold')" width="110px" sortable="custom" />
<el-table-column prop="freeGold" :label="$t('common_list.freeGold')" width="110px" sortable="custom" />
<el-table-column prop="taskGold" :label="$t('common_list.taskGold')" width="110px" sortable="custom" />
<el-table-column prop="remark" :label="$t('common_list.remark')" width="160px" show-overflow-tooltip />
<el-table-column prop="adminName" :label="$t('common_list.submitter')" width="100px" />
<el-table-column prop="auditTime" :label="$t('common_list.refundTime')" width="180px" sortable="custom">
<template #default="scope">
{{ moment(scope.row.auditTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
@ -623,33 +627,33 @@ const getMarket = async function () {
</el-card>
<!-- 导出弹窗 -->
<el-dialog v-model="exportListVisible" title="导出列表" width="80%">
<el-dialog v-model="exportListVisible" :title="$t('common_export.exportList')" width="80%">
<el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
<el-table-column prop="fileName" label="文件名" />
<el-table-column prop="state" label="状态">
<el-table-column prop="fileName" :label="$t('common_export.fileName')" />
<el-table-column prop="state" :label="$t('common_export.status')">
<template #default="scope">
<el-tag :type="getTagType(scope.row.state)" :effect="scope.row.state === 3 ? 'light' : 'plain'">
{{ getTagText(scope.row.state) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="auditTime" label="创建时间">
<el-table-column prop="auditTime" :label="$t('common_export.createTime')">
<template #default="scope">
{{ moment(scope.row.auditTime).format('YYYY-MM-DD HH:mm:ss') }}
</template>
</el-table-column>
<el-table-column label="操作">
<el-table-column :label="$t('common_export.operation')">
<template #default="scope">
<el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
:disabled="scope.row.state !== 2">
下载
{{ $t('common_export.download') }}
</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<div class="dialog-footer">
<el-button text @click="exportListVisible = false">关闭</el-button>
<el-button text @click="exportListVisible = false">{{ $t('common_export.close') }}</el-button>
</div>
</template>
</el-dialog>

Loading…
Cancel
Save