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

424 lines
14 KiB

2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
  1. <template>
  2. <el-card style="margin-bottom: 5px">
  3. <el-row style="margin-bottom: 10px">
  4. <el-col :span="6">
  5. <el-text size="large">精网号</el-text>
  6. <el-input v-model="searchForm.jwcode" placeholder="请输入精网号" style="width: 240px" clearable/>
  7. </el-col>
  8. <el-col :span="6">
  9. <el-text size="large">所属地区</el-text>
  10. <el-select v-model="searchForm.market" placeholder="请选择" style="width: 240px" clearable>
  11. <el-option v-for="item in marketOptions" :key="item" :label="item" :value="item"/>
  12. </el-select>
  13. </el-col>
  14. </el-row>
  15. <el-row>
  16. <el-col :span="15">
  17. <div class="time-controls">
  18. <div class="time-group">
  19. <el-text size="large" style="width: 80px">充值时间</el-text>
  20. <el-date-picker v-model="dateRange" type="datetimerange" range-separator=""
  21. start-placeholder="开始时间" end-placeholder="结束时间" style="width: 400px"
  22. @change="handleDatePickerChange" :default-time="defaultTime"/>
  23. <el-button @click="getToday()" style="margin-left: 10px"
  24. :type="activeTimeRange === 'today' ? 'primary' : ''">
  25. </el-button>
  26. <el-button @click="getYesterday()" style="margin-left: 10px"
  27. :type="activeTimeRange === 'yesterday' ? 'primary' : ''">
  28. </el-button>
  29. <el-button @click="get7Days()" style="margin-left: 10px"
  30. :type="activeTimeRange === '7days' ? 'primary' : ''"> 近7天
  31. </el-button>
  32. <el-button type="success" @click="resetSearch">重置</el-button>
  33. <el-button type="primary" @click="handleSearch">查询</el-button>
  34. </div>
  35. </div>
  36. </el-col>
  37. </el-row>
  38. </el-card>
  39. <el-card>
  40. <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
  41. <el-tab-pane label="待审核" name="wait"></el-tab-pane>
  42. <el-tab-pane label="已通过" name="pass"></el-tab-pane>
  43. <el-tab-pane label="已驳回" name="reject"></el-tab-pane>
  44. </el-tabs>
  45. <div>
  46. 总条数{{ stats.num }}&nbsp;&nbsp;&nbsp;&nbsp;
  47. 总金豆数{{ stats.beanNum }}金豆&nbsp;&nbsp;&nbsp;&nbsp;
  48. 永久金豆{{ stats.permanentBean }}金豆&nbsp;&nbsp;&nbsp;&nbsp;
  49. 免费金豆{{ stats.freeBean }}金豆
  50. </div>
  51. <el-table :data="tableData" height="540px" @sort-change="handleSortChange">
  52. <el-table-column prop="id" label="序号" width="80"/>
  53. <el-table-column prop="name" label="姓名" width="120" show-overflow-tooltip/>
  54. <el-table-column prop="jwcode" label="精网号" width="120"/>
  55. <el-table-column prop="market" label="所属地区" width="120"/>
  56. <el-table-column prop="permanentBean" label="付费金豆" width="120" sortable="custom"/>
  57. <el-table-column prop="freeBean" label="免费金豆" width="120" sortable="custom"/>
  58. <el-table-column prop="remark" label="备注" width="150" show-overflow-tooltip/>
  59. <el-table-column prop="submitName" label="提交人" width="120"/>
  60. <el-table-column v-if="checkTab === 'reject'" prop="reason" label="驳回理由" width="120"
  61. show-overflow-tooltip/>
  62. <el-table-column v-if="checkTab !== 'pending'" prop="auditName" label="审核人" width="120"/>
  63. <el-table-column prop="createTime" label="提交时间" width="180" sortable="custom">
  64. <template #default="{ row }">
  65. {{ moment(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
  66. </template>
  67. </el-table-column>
  68. <el-table-column v-if="checkTab !== 'pending'" prop="auditTime" label="审核时间" width="240" sortable="custom">
  69. <template #default="{ row }">
  70. {{ row.auditTime ? moment(row.auditTime).format('YYYY-MM-DD HH:mm:ss') : '--' }}
  71. </template>
  72. </el-table-column>
  73. <el-table-column v-if="checkTab === 'pending'" fixed="right" prop="operation" label="操作" width="400px">
  74. <template #default="scope">
  75. <div class="operation">
  76. <el-popconfirm title="确定要通过此条记录吗?" @confirm="handleApprove(scope.row)">
  77. <template #reference>
  78. <el-button :disabled="scope.row.status === 1 || scope.row.status === 2" type="primary"
  79. text>
  80. 通过
  81. </el-button>
  82. </template>
  83. </el-popconfirm>
  84. <el-button :disabled="scope.row.status === 1 || scope.row.status === 2" type="primary" text
  85. @click="showRejectDialog(scope.row)">
  86. 驳回
  87. </el-button>
  88. </div>
  89. </template>
  90. </el-table-column>
  91. </el-table>
  92. <el-pagination style="margin-top:20px" v-model:current-page="pagination.pageNum"
  93. v-model:page-size="pagination.pageSize" layout="total, sizes, prev, pager, next, jumper"
  94. :total="stats.num"
  95. @size-change="handlePageSizeChange" @current-change="handleCurrentChange"></el-pagination>
  96. </el-card>
  97. <el-dialog v-model="rejectDialogVisible" title="驳回理由" width="500px">
  98. <el-form>
  99. <el-form-item label="驳回理由" required>
  100. <el-input v-model="reason" type="textarea" :rows="4" placeholder="请输入驳回理由" maxlength="200"
  101. show-word-limit/>
  102. </el-form-item>
  103. </el-form>
  104. <template #footer>
  105. <span class="dialog-footer">
  106. <el-button @click="rejectDialogVisible = false">取消</el-button>
  107. <el-button type="primary" @click="handleReject()">确定</el-button>
  108. </span>
  109. </template>
  110. </el-dialog>
  111. </template>
  112. <script setup>
  113. import {onMounted, ref} from 'vue'
  114. import {ElMessage} from 'element-plus'
  115. import API from '@/util/http'
  116. import moment from 'moment'
  117. import {useAdminStore} from "@/store/index.js";
  118. import {storeToRefs} from "pinia";
  119. const defaultTime = [
  120. new Date(2000, 1, 1, 0, 0, 0),
  121. new Date(2000, 2, 1,23 , 59, 59),
  122. ]
  123. const adminStore = useAdminStore();
  124. const {adminData, menuTree} = storeToRefs(adminStore);
  125. import {permissionMapping, findMenuById} from "@/utils/menuTreePermission.js"
  126. import dayjs from "dayjs";
  127. const tableData = ref([])
  128. const marketOptions = ref([])
  129. const dateRange = ref([])
  130. const activeTimeRange = ref('')
  131. const activeName = ref('wait')
  132. const sortField = ref('')
  133. const sortOrder = ref('')
  134. const checkTab = ref('pending')
  135. const rejectDialogVisible = ref(false)
  136. const reason = ref('')
  137. const rejectRow = ref({
  138. id: null
  139. })// 驳回行数据
  140. // 状态常量
  141. const STATUS = {
  142. PENDING: 0, // 待审核
  143. APPROVED: 1, // 通过
  144. REJECTED: 2 // 驳回
  145. }
  146. const searchForm = ref({
  147. jwcode: '',
  148. market: '',
  149. createStartTime: '',
  150. createEndTime: '',
  151. status: STATUS.PENDING,
  152. auditStartTime: '',
  153. auditEndTime: ''
  154. })
  155. const pagination = ref({
  156. pageNum: 1,
  157. pageSize: 50
  158. })
  159. // 合计数
  160. const stats = ref({
  161. num: 0,
  162. beanNum: 0,
  163. permanentBean: 0,
  164. freeBean: 0
  165. })
  166. const showRejectDialog = (row) => {
  167. rejectRow.value.id = row.id
  168. reason.value = ''
  169. rejectDialogVisible.value = true
  170. }
  171. const getmarkets = async () => {
  172. try {
  173. const result = await API({url: '/beanConsume/getDept', data: {}})
  174. marketOptions.value = result.data || []
  175. } catch (error) {
  176. console.error('获取地区列表失败', error)
  177. }
  178. }
  179. const handleSortChange = (column) => {
  180. if (column.prop === 'permanentBean') {
  181. sortField.value = 'permanentBean'
  182. } else if (column.prop === 'freeBean') {
  183. sortField.value = 'freeBean'
  184. } else if (column.prop === 'createTime') {
  185. sortField.value = 'createTime'
  186. } else if (column.prop === 'auditTime') {
  187. sortField.value = 'auditTime'
  188. } else {
  189. sortField.value = ''
  190. }
  191. sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
  192. console.log('排序字段:', sortField.value)
  193. console.log('排序方式:', sortOrder.value)
  194. get()
  195. }
  196. const handleSearch = function () {
  197. if(searchForm.value.jwcode){
  198. const numRef = /^\d{1,9}$/;
  199. if(!numRef.test(searchForm.value.jwcode)){
  200. ElMessage.error('请检查精网号格式')
  201. return
  202. }
  203. }
  204. get()
  205. getStats()
  206. }
  207. const get = async function () {
  208. if (findMenuById(menuTree.value, permissionMapping.View_Golden_Bean_Recharge_Audit)) {
  209. try {
  210. if (dateRange.value && dateRange.value.length === 2) {
  211. searchForm.value.createStartTime = moment(dateRange.value[0]).format('YYYY-MM-DD HH:mm:ss')
  212. searchForm.value.createEndTime = moment(dateRange.value[1]).format('YYYY-MM-DD HH:mm:ss')
  213. } else {
  214. searchForm.value.createStartTime = ''
  215. searchForm.value.createEndTime = ''
  216. }
  217. const params = {
  218. pageNum: pagination.value.pageNum,//页码
  219. pageSize: pagination.value.pageSize,//页面大小
  220. beanAuditInfo: {
  221. jwcode: searchForm.value.jwcode,
  222. status: searchForm.value.status,
  223. market: searchForm.value.market,
  224. createStartTime: searchForm.value.createStartTime,
  225. createEndTime: searchForm.value.createEndTime,
  226. auditStartTime: searchForm.value.auditStartTime,
  227. auditEndTime: searchForm.value.auditEndTime,
  228. sortField: sortField.value,
  229. sortOrder: sortOrder.value
  230. }
  231. }
  232. console.log('看看传给后端的参数:', params)
  233. const res = await API({url: '/beanAudit/selectBy', data: params})
  234. tableData.value = res.data.list || []
  235. } catch (error) {
  236. console.error('获取数据失败', error)
  237. }
  238. } else {
  239. ElMessage.error('无此权限')
  240. }
  241. }
  242. const getStats = async () => {
  243. if (findMenuById(menuTree.value, permissionMapping.View_Golden_Bean_Recharge_Audit)) {
  244. try {
  245. const params = {
  246. jwcode: searchForm.value.jwcode,
  247. status: searchForm.value.status,
  248. market: searchForm.value.market,
  249. createStartTime: searchForm.value.createStartTime,
  250. createEndTime: searchForm.value.createEndTime,
  251. auditStartTime: searchForm.value.auditStartTime,
  252. auditEndTime: searchForm.value.auditEndTime
  253. }
  254. const res = await API({
  255. url: '/beanAudit/statsBean',
  256. data: params
  257. })
  258. stats.value.num = res.data.num
  259. stats.value.permanentBean = res.data.permanentBean
  260. stats.value.freeBean = res.data.freeBean
  261. stats.value.beanNum = res.data.beanNum
  262. console.log('see see stats和搜索对象', stats.value, params)
  263. } catch (error) {
  264. console.log('请求失败', error)
  265. }
  266. } else {
  267. ElMessage.error('无此权限')
  268. }
  269. }
  270. // 通过
  271. const handleApprove = async (row) => {
  272. if (findMenuById(menuTree.value, permissionMapping.Golden_Bean_Recharge_Approval)) {
  273. try {
  274. const params = {
  275. id: row.id,
  276. auditName: adminData.value.name,
  277. }
  278. await API({url: '/beanAudit/status1', data: params})
  279. ElMessage.success('审核通过成功')
  280. get()
  281. getStats()
  282. } catch (error) {
  283. console.error('审核通过失败', error)
  284. ElMessage.error('操作失败')
  285. }
  286. } else {
  287. ElMessage.error('无此权限')
  288. }
  289. }
  290. // 驳回
  291. const handleReject = async () => {
  292. if (findMenuById(menuTree.value, permissionMapping.Golden_Bean_Recharge_Approval)) {
  293. if (!reason.value.trim()) {
  294. ElMessage.warning('请输入驳回理由')
  295. return
  296. }
  297. try {
  298. const params = {
  299. id: rejectRow.value.id,
  300. auditName: adminData.value.adminName,
  301. reason: reason.value
  302. }
  303. await API({url: '/beanAudit/status2', data: params})
  304. ElMessage.success('驳回成功')
  305. rejectDialogVisible.value = false
  306. get()
  307. getStats()
  308. } catch (error) {
  309. console.error('驳回失败', error)
  310. ElMessage.error('操作失败')
  311. }
  312. } else {
  313. ElMessage.error('无此权限')
  314. }
  315. }
  316. const getToday = function () {
  317. const today = dayjs()
  318. const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
  319. const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
  320. dateRange.value = [startTime, endTime]
  321. console.log('dateRange', dateRange.value)
  322. activeTimeRange.value = 'today'
  323. get()
  324. getStats()
  325. }
  326. const getYesterday = function () {
  327. const today = dayjs()
  328. const startTime = today.subtract(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
  329. const endTime = today.subtract(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss')
  330. dateRange.value = [startTime, endTime]
  331. console.log('dateRange', dateRange.value)
  332. activeTimeRange.value = 'yesterday'
  333. get()
  334. getStats()
  335. }
  336. const get7Days = function () {
  337. const today = dayjs()
  338. const startTime = today.subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
  339. const endTime = today.add(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss')
  340. dateRange.value = [startTime, endTime]
  341. console.log('dateRange', dateRange.value)
  342. activeTimeRange.value = '7days'
  343. get()
  344. getStats()
  345. }
  346. const resetSearch = function () {
  347. const status = searchForm.value.status;
  348. searchForm.value = {
  349. jwcode: '',
  350. market: '',
  351. createStartTime: '',
  352. createEndTime: '',
  353. status: status,
  354. auditStartTime: '',
  355. auditEndTime: ''
  356. }
  357. dateRange.value = []
  358. activeTimeRange.value = '' // 清除激活状态
  359. }
  360. const handleClick = function (tab) {
  361. resetSearch()
  362. activeName.value = tab.props.name
  363. if (tab.props.name === 'wait') {
  364. adminWait()
  365. } else if (tab.props.name === 'pass') {
  366. adminPass()
  367. } else if (tab.props.name === 'reject') {
  368. adminReject()
  369. }
  370. }
  371. // 待审核充值明细
  372. const adminWait = async function () {
  373. checkTab.value = 'pending'
  374. searchForm.value.status = STATUS.PENDING
  375. await get()
  376. await getStats()
  377. }
  378. // 已通过充值明细
  379. const adminPass = async function () {
  380. checkTab.value = 'pass'
  381. searchForm.value.status = STATUS.APPROVED
  382. await get()
  383. await getStats()
  384. }
  385. // 已驳回充值明细
  386. const adminReject = async function () {
  387. checkTab.value = 'reject'
  388. searchForm.value.status = STATUS.REJECTED
  389. await get()
  390. await getStats()
  391. }
  392. const handleDatePickerChange = () => {
  393. activeTimeRange.value = ''
  394. }
  395. const handlePageSizeChange = function (val) {
  396. pagination.value.pageSize = val
  397. get()
  398. }
  399. const handleCurrentChange = function (val) {
  400. pagination.value.pageNum = val
  401. get()
  402. }
  403. onMounted(async () => {
  404. getmarkets()
  405. get()
  406. getStats()
  407. console.log("看看通信来的用户身份", adminData.value)
  408. })
  409. </script>
  410. <style scoped></style>