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.

674 lines
22 KiB

2 months ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
1 month ago
1 month ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
2 months ago
2 months ago
  1. <template>
  2. <el-row>
  3. <el-col>
  4. <div>
  5. <el-card style="margin-bottom: 5px">
  6. <el-row style="margin-bottom: 5px">
  7. <el-col :span="6">
  8. <el-text size="large">精网号</el-text>
  9. <el-input v-model="searchForm.jwcode" placeholder="请输入精网号" style="width: 240px" clearable/>
  10. </el-col>
  11. <el-col :span="6">
  12. <el-text size="large">商品名</el-text>
  13. <el-select v-model="searchForm.goodsName" placeholder="请输入商品名" style="width: 240px" clearable>
  14. <el-option v-for="item in refundGoodsOptions" :key="item" :label="item" :value="item"></el-option>
  15. </el-select>
  16. </el-col>
  17. <el-col :span="6">
  18. <el-text size="large">退款方式</el-text>
  19. <el-select v-model="searchForm.refundModel" placeholder="请选择" style="width: 240px" clearable>
  20. <el-option label="全部退款" value="0"/>
  21. <el-option label="部分退款" value="1"/>
  22. </el-select>
  23. </el-col>
  24. <el-col :span="6">
  25. <el-text class="mx-1" size="large">所属地区</el-text>
  26. <el-cascader
  27. v-model="selectedMarketPath"
  28. :options="markets"
  29. placeholder="请选择所属地区"
  30. clearable
  31. collapse-tags
  32. collapse-tags-tooltip
  33. style="width:180px"
  34. @change="handleMarketChange"
  35. :props="props"
  36. />
  37. </el-col>
  38. </el-row>
  39. <el-row>
  40. <el-col :span="15">
  41. <div class="time-controls">
  42. <div class="time-group">
  43. <el-text size="large" style="width: 80px">提交时间</el-text>
  44. <el-date-picker v-model="dateRange" type="datetimerange" range-separator=""
  45. start-placeholder="开始时间"
  46. end-placeholder="结束时间" style="width: 400px" @change="handleDatePickerChange"/>
  47. <el-button @click="getToday()" style="margin-left: 10px"
  48. :type="activeTimeRange === 'today' ? 'primary' : ''">
  49. </el-button>
  50. <el-button @click="getYesterday()" style="margin-left: 10px"
  51. :type="activeTimeRange === 'yesterday' ? 'primary' : ''">
  52. </el-button>
  53. <el-button @click="get7Days()" style="margin-left: 10px"
  54. :type="activeTimeRange === '7days' ? 'primary' : ''"> 近7天
  55. </el-button>
  56. <el-button type="success" @click="resetSearch">重置</el-button>
  57. <el-button type="primary" @click="handleSearch">查询</el-button>
  58. </div>
  59. </div>
  60. </el-col>
  61. </el-row>
  62. </el-card>
  63. </div>
  64. </el-col>
  65. </el-row>
  66. <el-card>
  67. <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
  68. <el-tab-pane label="待审核" name="wait"></el-tab-pane>
  69. <el-tab-pane label="已通过" name="pass"></el-tab-pane>
  70. <el-tab-pane label="已驳回" name="reject"></el-tab-pane>
  71. </el-tabs>
  72. <div>
  73. 总条数{{ stats.totalNum }}&nbsp;&nbsp;&nbsp;&nbsp;
  74. 退款总金币数{{ (stats.permanentGolds + stats.freeGolds + stats.taskGolds).toFixed(2) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
  75. 永久金币{{ stats.permanentGolds.toFixed(2) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
  76. 免费金币{{ stats.freeGolds.toFixed(2) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
  77. 任务金币{{ stats.taskGolds.toFixed(2) }}金币
  78. </div>
  79. <el-table :data="tableData" height="540px" @sort-change="handleSortChange">
  80. <el-table-column type="index" label="序号" width="60"/>
  81. <el-table-column prop="name" label="姓名" width="120"/>
  82. <el-table-column prop="jwcode" label="精网号" width="120"/>
  83. <el-table-column prop="market" label="所属地区" width="120">
  84. <template #default="scope">
  85. {{ marketMapping[scope.row.market] || scope.row.market }}
  86. </template>
  87. </el-table-column>
  88. <el-table-column prop="refundType" label="退款类型" width="120"/>
  89. <el-table-column prop="refundModel" label="退款方式" width="120">
  90. <template #default="{ row }">
  91. {{ row.refundModel === 0 ? '全部退款' : '部分退款' }}
  92. </template>
  93. </el-table-column>
  94. <el-table-column prop="goodsName" label="退款商品" width="120" show-overflow-tooltip/>
  95. <el-table-column prop="sumGold" label="退款金额" width="120" sortable="custom">
  96. <template #default="{ row }">
  97. {{ row.sumGold / 100 }}
  98. </template>
  99. </el-table-column>
  100. <el-table-column prop="permanentGold" label="永久金币" width="120" sortable="custom">
  101. <template #default="{ row }">
  102. {{ row.permanentGold / 100 }}
  103. </template>
  104. </el-table-column>
  105. <el-table-column prop="freeGold" label="免费金币" width="120" sortable="custom">
  106. <template #default="{ row }">
  107. {{ (row.freeJune + row.freeDecember) / 100 }}
  108. </template>
  109. </el-table-column>
  110. <el-table-column prop="taskGold" label="任务金币" width="120" sortable="custom">
  111. <template #default="{ row }">
  112. {{ row.taskGold / 100 }}
  113. </template>
  114. </el-table-column>
  115. <el-table-column prop="remark" label="备注" width="150" show-overflow-tooltip/><!-- 当内容过长被隐藏时显示 tooltip -->
  116. <el-table-column prop="adminName" label="提交人" width="120"/>
  117. <el-table-column v-if="checkTab === 'reject'" prop="rejectReason" label="驳回理由" width="150"
  118. show-overflow-tooltip/>
  119. <el-table-column v-if="checkTab !== 'pending'" prop="auditName" label="审核人" width="120"/>
  120. <el-table-column prop="createTime" label="提交时间" width="180" sortable="custom">
  121. <template #default="{ row }">
  122. {{ moment(row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
  123. </template>
  124. </el-table-column>
  125. <el-table-column v-if="checkTab !== 'pending'" prop="auditTime" label="审核时间" width="180" sortable="custom">
  126. <template #default="{ row }">
  127. {{ row.auditTime ? moment(row.auditTime).format('YYYY-MM-DD HH:mm:ss') : '--' }}
  128. </template>
  129. </el-table-column>
  130. <el-table-column v-if="checkTab === 'pending'" fixed="right" prop="operation" label="操作" width="150px">
  131. <template #default="scope">
  132. <div class="operation">
  133. <el-popconfirm title="确定要通过此条记录吗?" @confirm="handleApprove(scope.row)">
  134. <template #reference>
  135. <el-button :disabled="scope.row.auditStatus === 1 || scope.row.auditStatus === 2" type="primary" text>
  136. 通过
  137. </el-button>
  138. </template>
  139. </el-popconfirm>
  140. <el-button :disabled="scope.row.auditStatus === 1 || scope.row.auditStatus === 2" type="primary" text
  141. @click="showRejectDialog(scope.row)">
  142. 驳回
  143. </el-button>
  144. </div>
  145. </template>
  146. </el-table-column>
  147. </el-table>
  148. <el-pagination class="pagination" v-model:current-page="pagination.pageNum" v-model:page-size="pagination.pageSize"
  149. layout="total, sizes, prev, pager, next, jumper" :total="pagination.total"
  150. @size-change="handlePageSizeChange"
  151. @current-change="handleCurrentChange"></el-pagination>
  152. </el-card>
  153. <el-dialog v-model="rejectDialogVisible" title="驳回理由" width="500px">
  154. <el-form>
  155. <el-form-item label="驳回理由" required>
  156. <el-input v-model="rejectReason" type="textarea" :rows="4" placeholder="请输入驳回理由" maxlength="200"
  157. show-word-limit/>
  158. </el-form-item>
  159. </el-form>
  160. <template #footer>
  161. <span class="dialog-footer">
  162. <el-button @click="rejectDialogVisible = false">取消</el-button>
  163. <el-button type="primary" @click="handleReject">确定</el-button>
  164. </span>
  165. </template>
  166. </el-dialog>
  167. </template>
  168. <script setup>
  169. import {onMounted, reactive, ref} from 'vue'
  170. import {ElMessage} from 'element-plus'
  171. import API from '@/util/http.js'
  172. import moment from 'moment'
  173. import {marketMapping, reverseMarketMapping} from "@/utils/marketMap.js";
  174. // 标记当前激活的时间范围按钮
  175. const activeTimeRange = ref('')
  176. // 日期选择器变化时清除按钮激活状态
  177. const handleDatePickerChange = () => {
  178. activeTimeRange.value = ''
  179. }
  180. const scopeValue = ref(null) // 当前行
  181. const rejectDialogVisible = ref(false) // 驳回对话框显示状态
  182. const rejectReason = ref('') // 驳回理由
  183. // 状态常量
  184. const STATUS = {
  185. PENDING: 0, // 待审核
  186. APPROVED: 1, // 通过
  187. REJECTED: 2 // 驳回
  188. }
  189. // 搜索表单数据
  190. const searchForm = ref({
  191. jwcode: '',
  192. refundModel: '',
  193. goodsName: '',
  194. markets: [],
  195. startTime: '',
  196. endTime: '',
  197. auditStatus: '0'
  198. })
  199. const checkTab = ref('pending') // 能否不用STATUS常量,0是待审批,1是已通过,2是驳回,参数status需要Integer
  200. // 时间
  201. const dateRange = ref([])
  202. const pagination = ref({
  203. pageNum: 1,
  204. pageSize: 50,
  205. total: 0
  206. })
  207. const tableData = ref([])
  208. const marketOptions = ref([])
  209. const refundGoodsOptions = ref([])
  210. const adminInfo = ref({})
  211. // 统计合计数
  212. const stats = ref({
  213. totalNum: 0,
  214. totalCoins: 0,
  215. permanentGolds: 0,
  216. freeGolds: 0,
  217. taskGolds: 0
  218. })
  219. // 驳回弹出框
  220. const rejectVisible = ref(false)
  221. // 驳回对象
  222. const rejectObj = ref({})
  223. // 通过对象
  224. const passObj = ref({})
  225. // 标签页默认是待审批
  226. const activeName = ref('wait')
  227. // 表单验证ref
  228. const Ref = ref(null)
  229. // 新增排序字段和排序方式
  230. const sortField = ref('')
  231. const sortOrder = ref('')
  232. // 表单验证
  233. const rules = reactive({
  234. reason: [{required: true, message: '请输入驳回理由', trigger: 'blur'}]
  235. })
  236. const getAdminData = async function () {
  237. try {
  238. const result = await API({url: '/admin/userinfo', data: {}})
  239. adminInfo.value = result
  240. console.log('请求成功', result)
  241. console.log('用户信息', adminInfo.value)
  242. } catch (error) {
  243. console.log('请求失败', error)
  244. }
  245. }
  246. const handlePageSizeChange = function (val) {
  247. pagination.value.pageSize = val
  248. get()
  249. console.log('aaaaaaaaaaaaaaaaaa这是pageSize改变调用')
  250. }
  251. const handleCurrentChange = function (val) {
  252. pagination.value.pageNum = val
  253. get()
  254. console.log('aaaaaaaaaaaaaaa这是pageNum改变调用')
  255. }
  256. // 处理排序事件
  257. const handleSortChange = (column) => {
  258. if (column.prop === 'sumGold') {
  259. sortField.value = 'sum_gold'
  260. } else if (column.prop === 'permanentGold') {
  261. sortField.value = 'permanent_gold'
  262. } else if (column.prop === 'freeGold') {
  263. sortField.value = 'freeGold'
  264. } else if (column.prop === 'taskGold') {
  265. sortField.value = 'task_gold'
  266. } else if (column.prop === 'createTime') {
  267. sortField.value = 'create_time'
  268. } else if (column.prop === 'auditTime') {
  269. sortField.value = 'audit_time'
  270. } else {
  271. sortField.value = ''
  272. }
  273. sortOrder.value = column.order === 'ascending' ? 'asc' : 'desc'
  274. console.log('排序字段:', sortField.value)
  275. console.log('排序方式:', sortOrder.value)
  276. get()
  277. }
  278. // 显示驳回对话框
  279. const showRejectDialog = (row) => {
  280. scopeValue.value = row
  281. rejectReason.value = ''
  282. rejectDialogVisible.value = true
  283. }
  284. // 查地区
  285. const markets = ref([])
  286. // 查商品名
  287. const getRefundGoods = async () => {
  288. try {
  289. const res = await API({url: '/general/goods'})
  290. refundGoodsOptions.value = res.data || []
  291. } catch (error) {
  292. console.error('获取商品列表失败', error)
  293. }
  294. }
  295. // 搜索方法
  296. const get = async function (val) {
  297. try {
  298. if (typeof val === 'number') {
  299. pagination.value.pageNum = val
  300. }
  301. if (dateRange.value && dateRange.value.length === 2) {
  302. searchForm.value.startTime = moment(dateRange.value[0]).format('YYYY-MM-DD HH:mm:ss')
  303. searchForm.value.endTime = moment(dateRange.value[1]).format('YYYY-MM-DD HH:mm:ss')
  304. } else {
  305. searchForm.value.startTime = ''
  306. searchForm.value.endTime = ''
  307. }
  308. const params = {
  309. pageNum: pagination.value.pageNum,
  310. pageSize: pagination.value.pageSize,
  311. refundAudit: {
  312. ...searchForm.value,
  313. sortField: sortField.value,
  314. sortOrder: sortOrder.value
  315. }
  316. }
  317. console.log('看看传给后端的参数:', params)
  318. const res = await API({url: '/audit/selectRefund', data: params})
  319. tableData.value = res.list || []
  320. pagination.value.total = res.total || 0
  321. console.log('查全部的total', pagination.value.total, res.total)
  322. } catch (error) {
  323. console.error('获取数据失败', error)
  324. }
  325. }
  326. import {useAdminStore} from "@/store/index.js";
  327. import {storeToRefs} from "pinia";
  328. import {findMenuById, permissionMapping} from "@/utils/menuTreePermission.js"
  329. import dayjs from "dayjs";
  330. const adminStore = useAdminStore();
  331. const {menuTree} = storeToRefs(adminStore);
  332. // 通过
  333. const handleApprove = async (row) => {
  334. if (findMenuById(menuTree.value, permissionMapping.Refund_Approval)) {
  335. try {
  336. const params = {
  337. orderCode: row.orderCode,
  338. auditId: adminInfo.value.id,
  339. action: 1,// action的1是通过,2是驳回
  340. rejectReason: ''
  341. }
  342. await API({url: '/audit/audit', data: params})// 试一下能不能发
  343. ElMessage.success('审核通过成功')
  344. get()
  345. getStats()
  346. console.log('aaaaaaaaaa这是通过调用')
  347. } catch (error) {
  348. console.error('审核通过失败', error)
  349. ElMessage.error('操作失败')
  350. }
  351. } else {
  352. ElMessage.warning('没有权限')
  353. }
  354. }
  355. // 处理驳回操作
  356. const handleReject = async () => {
  357. if (findMenuById(menuTree.value, permissionMapping.Refund_Approval)) {
  358. if (!rejectReason.value.trim()) {
  359. ElMessage.warning('请输入驳回理由')
  360. return
  361. }
  362. try {
  363. const params = {
  364. orderCode: scopeValue.value.orderCode,
  365. auditId: adminInfo.value.id,
  366. action: 2,
  367. rejectReason: rejectReason.value
  368. }
  369. await API({url: '/audit/audit', data: params})
  370. ElMessage.success('驳回成功')
  371. rejectDialogVisible.value = false
  372. get()
  373. getStats()
  374. console.log('aaaaaaaaaa这是驳回调用', params)
  375. } catch (error) {
  376. console.error('驳回失败', error)
  377. ElMessage.error('操作失败')
  378. }
  379. } else {
  380. ElMessage.warning('没有权限')
  381. }
  382. }
  383. const getStats = async () => {
  384. try {
  385. const params = {
  386. pageNum: pagination.value.pageNum,
  387. pageSize: pagination.value.pageSize,
  388. refundAudit: {
  389. ...searchForm.value
  390. }
  391. }
  392. const res = await API({
  393. url: '/audit/sumRefundGold',
  394. data: params
  395. })
  396. stats.value.totalNum = res.totalNum
  397. stats.value.permanentGolds = res.permanentGolds / 100
  398. stats.value.freeGolds = res.freeGolds / 100
  399. stats.value.taskGolds = res.taskGolds / 100
  400. console.log('see see stats和搜索对象', stats.value, params)
  401. } catch (error) {
  402. console.log('请求失败', error)
  403. }
  404. }
  405. // 搜索
  406. const handleSearch = function () {
  407. // pagination.value.pageNum = 1
  408. get()
  409. getStats()
  410. console.log('aaaaaaaaaa这是搜索按钮调用')
  411. }
  412. // 重置
  413. const resetSearch = function () {
  414. const auditStatus = searchForm.value.auditStatus;
  415. searchForm.value = {
  416. jwcode: '',
  417. refundType: '',
  418. goodsName: '',
  419. markets: [],
  420. startTime: '',
  421. endTime: '',
  422. sortField: '',
  423. sortOrder: '',
  424. auditStatus: auditStatus
  425. }
  426. dateRange.value = []
  427. activeTimeRange.value = '' // 清除激活状态
  428. selectedMarketPath.value = []
  429. get()
  430. getStats()
  431. }
  432. // 今天
  433. const getToday = function () {
  434. const today = dayjs()
  435. const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
  436. const endTime =today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
  437. dateRange.value = [startTime, endTime]
  438. console.log('dateRange', dateRange.value)
  439. activeTimeRange.value = 'today' // 标记当前激活状态
  440. get()
  441. getStats()
  442. console.log('aaaaaaaaaa这是今天调用')
  443. }
  444. // 昨天
  445. const getYesterday = function () {
  446. const today = dayjs()
  447. const startTime = today.subtract(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
  448. const endTime = today.subtract(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss')
  449. dateRange.value = [startTime, endTime]
  450. console.log('dateRange', dateRange.value)
  451. activeTimeRange.value = 'yesterday' // 标记当前激活状态
  452. get()
  453. getStats()
  454. console.log('aaaaaaaaaa这是昨天调用')
  455. }
  456. // 近7天
  457. const get7Days = function () {
  458. const today = dayjs()
  459. const startTime = today.subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
  460. const endTime = today.add(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss')
  461. dateRange.value = [startTime, endTime]
  462. console.log('dateRange', dateRange.value)
  463. activeTimeRange.value = '7days' // 标记当前激活状态
  464. get()
  465. getStats()
  466. console.log('aaaaaaaaaa这是近七天调用')
  467. }
  468. // 切换标签页
  469. const handleClick = function (tab, event) {
  470. activeName.value = tab.props.name
  471. if (tab.props.name === 'wait') {
  472. adminWait()
  473. } else if (tab.props.name === 'pass') {
  474. adminPass()
  475. } else if (tab.props.name === 'reject') {
  476. adminReject()
  477. }
  478. }
  479. // 当前状态
  480. const getCurrentStatus = () => {
  481. switch (activeName.value) {
  482. case 'wait':
  483. return STATUS.PENDING
  484. case 'pass':
  485. return STATUS.APPROVED
  486. case 'reject':
  487. return STATUS.REJECTED
  488. default:
  489. return ''
  490. }
  491. }
  492. // 待审核充值明细
  493. const adminWait = async function () {
  494. checkTab.value = 'pending'
  495. searchForm.value.auditStatus = STATUS.PENDING
  496. // pagination.value.pageNum = 1
  497. await get()
  498. await getStats()
  499. console.log('aaaaaaaaaaaaaaaaa看看checkTab,这是点击待审核调用', checkTab.value)
  500. }
  501. // 已通过充值明细
  502. const adminPass = async function () {
  503. checkTab.value = 'pass'
  504. searchForm.value.auditStatus = STATUS.APPROVED
  505. // pagination.value.pageNum = 1
  506. await get()
  507. await getStats()
  508. console.log('aaaaaaaaaaaaaaaaaaaaa看看checkTab,这是点击已通过调用', checkTab.value)
  509. }
  510. // 已驳回充值明细
  511. const adminReject = async function () {
  512. checkTab.value = 'reject'
  513. searchForm.value.auditStatus = STATUS.REJECTED
  514. // pagination.value.pageNum = 1
  515. await get()
  516. await getStats()
  517. console.log('aaaaaaaaaaaaaaaaaa看看checkTab,这是点击已驳回调用', checkTab.value)
  518. }
  519. // 存储地区选择变化
  520. const selectedMarketPath = ref([])
  521. //处理地区选择变化
  522. const handleMarketChange = (value) => {
  523. if (Array.isArray(value) && value.length > 0) {
  524. const ids = new Set();
  525. value.forEach(path => {
  526. const lastName = path[path.length - 1];
  527. const id = reverseMarketMapping[lastName];
  528. if (id) ids.add(Number(id));
  529. });
  530. // 添加额外处理:如果一个父节点下所有子节点都被选中,则把父节点也加入
  531. const getAllLeafNames = (nodes) => {
  532. const leafNames = [];
  533. const traverse = (node, parentName = null) => {
  534. if (!node.children || node.children.length === 0) {
  535. leafNames.push({name: node.label, parent: parentName});
  536. } else {
  537. node.children.forEach(child => traverse(child, node.label));
  538. }
  539. };
  540. nodes.forEach(node => traverse(node));
  541. return leafNames;
  542. };
  543. const leafNameMap = getAllLeafNames(markets.value); // 所有叶子节点和对应父级名称
  544. // 列表构建
  545. const parentToChildren = {};
  546. leafNameMap.forEach(({name, parent}) => {
  547. if (!parentToChildren[parent]) parentToChildren[parent] = [];
  548. parentToChildren[parent].push(name);
  549. });
  550. // 构建当前被选中的叶子节点
  551. const selectedLeafNames = value.map(path => path[path.length - 1]);
  552. // 如果 parent 下所有子节点都选中了,就把 parent 加进来
  553. Object.entries(parentToChildren).forEach(([parent, children]) => {
  554. const allChildrenSelected = children.every(child => selectedLeafNames.includes(child));
  555. if (allChildrenSelected && reverseMarketMapping[parent]) {
  556. ids.add(Number(reverseMarketMapping[parent]));
  557. }
  558. });
  559. searchForm.value.markets = Array.from(ids);
  560. } else {
  561. searchForm.value.markets = [];
  562. }
  563. console.log('最终映射后的 market IDs:', searchForm.value.markets);
  564. };
  565. const props = {multiple: true}
  566. // 获取地区,修改为级联下拉框
  567. const getMarket = async function () {
  568. try {
  569. // 发送POST请求
  570. const result = await API({
  571. url: '/market/selectMarket',
  572. });
  573. // 将响应结果存储到响应式数据中
  574. console.log('请求成功', result)
  575. // 递归转换树形结构为级联选择器需要的格式(跳过第一级节点)
  576. const transformTree = (nodes) => {
  577. // 直接处理第一级节点的子节点
  578. const allChildren = nodes.flatMap(node => node.children || []);
  579. return allChildren.map(child => {
  580. const grandchildren = child.children && child.children.length
  581. ? transformTree([child]) // 递归处理子节点
  582. : null;
  583. return {
  584. value: child.name,
  585. label: child.name,
  586. children: grandchildren
  587. };
  588. });
  589. };
  590. // 存储地区信息
  591. markets.value = transformTree(result.data)
  592. console.log('转换后的地区树==============', markets.value)
  593. } catch (error) {
  594. console.log('请求失败', error)
  595. }
  596. }
  597. onMounted(async () => {
  598. await getAdminData()
  599. getRefundGoods()
  600. await getMarket()
  601. await get()
  602. await getStats()
  603. console.log('aaaaaaaaaa这是挂载后调用')
  604. })
  605. </script>
  606. <style scoped>
  607. .pagination {
  608. display: flex;
  609. }
  610. .operation {
  611. display: flex;
  612. }
  613. .time-controls {
  614. display: flex;
  615. align-items: center;
  616. }
  617. .time-group {
  618. display: flex;
  619. align-items: center;
  620. gap: 10px;
  621. }
  622. </style>