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.

712 lines
23 KiB

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
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
1 month ago
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
  1. <script setup>
  2. import {ref, onMounted, reactive, computed} from 'vue'
  3. import ElementPlus from 'element-plus'
  4. import {ElMessage, ElMessageBox} from 'element-plus'
  5. import {AiFillRead} from 'vue-icons-plus/ai'
  6. import axios from 'axios'
  7. import moment from 'moment'
  8. import API from '@/util/http.js'
  9. import {marketMapping, reverseMarketMapping} from '@/utils/marketMap.js';
  10. import dayjs from "dayjs";
  11. //这是获取用户信息的接口
  12. const adminData = ref({})
  13. const getAdminData = async function () {
  14. try {
  15. const result = await API({url: '/admin/userinfo', data: {}})
  16. adminData.value = result
  17. rechargeUser.value.adminId = adminData.value.id
  18. console.log('请求成功', result)
  19. console.log('用户信息', adminData.value)
  20. } catch (error) {
  21. console.log('请求失败', error)
  22. }
  23. }
  24. const defaultTime = [
  25. new Date(2000, 1, 1, 0, 0, 0),
  26. new Date(2000, 2, 1,23 , 59, 59),
  27. ]
  28. // 变量
  29. // 充值明细表格
  30. const tableData = ref([])
  31. // 标记当前激活的时间范围按钮
  32. const activeTimeRange = ref('')
  33. // 日期选择器变化时清除按钮激活状态
  34. const handleDatePickerChange = () => {
  35. activeTimeRange.value = ''
  36. }
  37. // 搜索===========================================
  38. // 搜索recharge
  39. const rechargeUser = ref({
  40. adminId: adminData.value.id,
  41. markets: [],
  42. })
  43. // 存储地区选择变化
  44. const selectedMarketPath = ref([])
  45. //处理地区选择变化
  46. const handleMarketChange = (value) => {
  47. if (Array.isArray(value) && value.length > 0) {
  48. const ids = new Set();
  49. value.forEach(path => {
  50. const lastName = path[path.length - 1];
  51. const id = reverseMarketMapping[lastName];
  52. if (id) ids.add(Number(id));
  53. });
  54. // 添加额外处理:如果一个父节点下所有子节点都被选中,则把父节点也加入
  55. const getAllLeafNames = (nodes) => {
  56. const leafNames = [];
  57. const traverse = (node, parentName = null) => {
  58. if (!node.children || node.children.length === 0) {
  59. leafNames.push({ name: node.label, parent: parentName });
  60. } else {
  61. node.children.forEach(child => traverse(child, node.label));
  62. }
  63. };
  64. nodes.forEach(node => traverse(node));
  65. return leafNames;
  66. };
  67. const leafNameMap = getAllLeafNames(markets.value); // 所有叶子节点和对应父级名称
  68. // 构建一个 { parentName: [childName1, childName2, ...] } 的结构
  69. const parentToChildren = {};
  70. leafNameMap.forEach(({ name, parent }) => {
  71. if (!parentToChildren[parent]) parentToChildren[parent] = [];
  72. parentToChildren[parent].push(name);
  73. });
  74. // 构建当前被选中的叶子节点
  75. const selectedLeafNames = value.map(path => path[path.length - 1]);
  76. // 如果 parent 下所有子节点都选中了,就把 parent 加进来
  77. Object.entries(parentToChildren).forEach(([parent, children]) => {
  78. const allChildrenSelected = children.every(child => selectedLeafNames.includes(child));
  79. if (allChildrenSelected && reverseMarketMapping[parent]) {
  80. ids.add(Number(reverseMarketMapping[parent]));
  81. }
  82. });
  83. rechargeUser.value.markets = Array.from(ids);
  84. } else {
  85. rechargeUser.value.markets = [];
  86. }
  87. console.log('最终映射后的 market IDs:', rechargeUser.value.markets);
  88. };
  89. // 搜索对象
  90. const getObj = ref({
  91. pageNum: 1,
  92. pageSize: 50
  93. })
  94. //分页总条目
  95. const total = ref(100)
  96. // 搜索对象时间
  97. const getTime = ref([])
  98. // 搜索活动列表
  99. const activity = ref([])
  100. // 所有信息
  101. const allData = ref([])
  102. // 搜索地区列表
  103. const markets = ref([])
  104. //时间格式化
  105. const formatTime = (val) => val ? moment(val).format('YYYY-MM-DD HH:mm:ss') : ''
  106. // 初始化 money 和 permanentGold 和 freeGold
  107. const money = ref(0)
  108. const permanentGold = ref(0)
  109. const freeGold = ref(0)
  110. // 定义响应式变量存储金币合计数
  111. const permanentGolds = ref(0)
  112. const freeGolds = ref(0)
  113. // 支付方式选项
  114. const payModel = [
  115. {
  116. value: '微信',
  117. label: '微信'
  118. },
  119. {
  120. value: '支付宝',
  121. label: '支付宝'
  122. },
  123. {
  124. value: '银联',
  125. label: '银联'
  126. },
  127. {
  128. value: '信用卡',
  129. label: '信用卡'
  130. },
  131. {
  132. value: '借记卡',
  133. label: '借记卡'
  134. },
  135. {
  136. value: '现金充值',
  137. label: '现金充值'
  138. }
  139. ]
  140. // 删除==========================================================
  141. // 删除对象
  142. const delObj = ref({})
  143. // 获取活动名称
  144. const getActivity = async function () {
  145. try {
  146. // 发送POST请求
  147. const result = await API({url: '/general/activity', data: {}})
  148. // 将响应结果存储到响应式数据中
  149. console.log('请求成功', result)
  150. // 检查返回的数据是否为数组
  151. if (Array.isArray(result.data)) {
  152. // 将字符串数组转换为 { value, label } 格式
  153. activity.value = result.data.map(item => ({value: item, label: item}));
  154. } else {
  155. console.error('活动数据格式错误', result)
  156. ElMessage.error('活动数据格式错误,请联系管理员')
  157. }
  158. console.log('activity', activity.value)
  159. } catch (error) {
  160. console.log('请求失败', error)
  161. // 在这里可以处理错误逻辑,比如显示错误提示等
  162. }
  163. }
  164. const marketsTree = ref("")
  165. // 获取地区,修改为级联下拉框
  166. const getArea = async function () {
  167. try {
  168. // 发送POST请求
  169. const result = await API({
  170. url: '/market/selectMarket',
  171. });
  172. // 将响应结果存储到响应式数据中
  173. console.log('请求成功', result)
  174. // 递归转换树形结构为级联选择器需要的格式(跳过第一级节点)
  175. const transformTree = (nodes) => {
  176. // 直接处理第一级节点的子节点
  177. const allChildren = nodes.flatMap(node => node.children || []);
  178. return allChildren.map(child => {
  179. const grandchildren = child.children && child.children.length
  180. ? transformTree([child]) // 递归处理子节点
  181. : null;
  182. return {
  183. value: child.name,
  184. label: child.name,
  185. children: grandchildren
  186. };
  187. });
  188. };
  189. // 存储地区信息
  190. markets.value = transformTree(result.data)
  191. console.log('转换后的地区树==============', markets.value)
  192. } catch (error) {
  193. console.log('请求失败', error)
  194. }
  195. }
  196. //定义充值方式的加载状态
  197. const isLoadingPlatform = ref(false)
  198. // 充值方式
  199. const platform = ref([])
  200. //获取充值方式的函数
  201. const getPlatform = async () => {
  202. isLoadingPlatform.value = true;
  203. try {
  204. const result = await API({
  205. url: '/general/platform',
  206. method: 'post',
  207. data: {}// 这里添加参数
  208. })
  209. // 假设后端返回的是字符串数组,转换为 { value, label } 格式
  210. if (Array.isArray(result.data)) {
  211. platform.value = result.data.map(item => ({value: item, label: item}));
  212. } else {
  213. console.error('充值方式格式错误', result)
  214. ElMessage.error('充值方式格式错误,请联系管理员')
  215. }
  216. } catch (error) {
  217. console.error('获取充值方式失败:', error);
  218. ElMessage.error('获取充值方式失败,请稍后重试');
  219. } finally {
  220. isLoadingPlatform.value = false
  221. }
  222. }
  223. // 搜索===========================================================================
  224. // 搜索方法
  225. const get = async function (val) {
  226. try {
  227. // 搜索参数页码赋值
  228. if (typeof val === 'number') {
  229. getObj.value.pageNum = val
  230. }
  231. // 搜索参数时间赋值
  232. if (getTime.value != null) {
  233. if (getTime.value.startTime != '' && getTime.value.endTime != '') {
  234. rechargeUser.value.startTime = formatTime(getTime.value[0])
  235. rechargeUser.value.endTime = formatTime(getTime.value[1])
  236. }
  237. } else {
  238. rechargeUser.value.startTime = ''
  239. rechargeUser.value.endTime = ''
  240. }
  241. // 搜索参数赋值
  242. rechargeUser.value.sortField = sortField.value
  243. rechargeUser.value.sortOrder = sortOrder.value
  244. console.log('搜索参数', getObj.value)
  245. // 发送POST请求
  246. const result = await API({
  247. url: '/recharge/selectBy',
  248. data: {
  249. ...getObj.value,
  250. rechargeUser: {...rechargeUser.value}
  251. }
  252. })
  253. // 复制一份 rechargeUser.value 并移除排序字段和排序方式
  254. const detailWithoutSort = ref({
  255. markets: rechargeUser.value.markets,
  256. activity: rechargeUser.value.activity,
  257. adminId: rechargeUser.value.adminId,
  258. startTime: rechargeUser.value.startTime,
  259. endTime: rechargeUser.value.endTime,
  260. jwcode: rechargeUser.value.jwcode,
  261. goodsName: rechargeUser.value.goodsName,
  262. payPlatform: rechargeUser.value.payPlatform
  263. })
  264. const resultTotalGold = await API({
  265. url: '/recharge/statsGold',
  266. data: {
  267. ...detailWithoutSort.value
  268. }
  269. })
  270. if (resultTotalGold.code === 200 && resultTotalGold.data) {
  271. const data = resultTotalGold.data
  272. console.log('获取到的金币数据:', data)
  273. permanentGolds.value = (Number(data.permanentGolds) || 0)
  274. freeGolds.value = (Number(data.freeGolds) || 0)
  275. }
  276. // 将响应结果存储到响应式数据中
  277. console.log('请求成功', result)
  278. // 存储表格数据
  279. tableData.value = result.data.list
  280. // 处理表格中的充值金额、永久金币和免费金币数据,除以 100
  281. tableData.value = tableData.value.map(item => ({
  282. ...item,
  283. // 处理永久金币
  284. permanentGold: (Number(item.permanentGold) || 0) / 100,
  285. // 处理免费金币
  286. freeGold: (Number(item.freeGold) || 0) / 100,
  287. // 处理充值金额
  288. money: (Number(item.money) || 0) / 100
  289. }))
  290. console.log('tableData', tableData.value)
  291. // 存储分页总数
  292. total.value = result.data.total
  293. console.log('total', total.value)
  294. } catch (error) {
  295. console.log('请求失败', error)
  296. // 在这里可以处理错误逻辑,比如显示错误提示等
  297. }
  298. }
  299. // 搜索
  300. const search = function () {
  301. getObj.value.pageNum = 1
  302. get()
  303. }
  304. // 重置
  305. const reset = function () {
  306. delete rechargeUser.value.jwcode
  307. delete rechargeUser.value.activity
  308. delete rechargeUser.value.payPlatform
  309. rechargeUser.value.markets = []
  310. selectedMarketPath.value = [] // 重置地区选择路径
  311. delete rechargeUser.value.startTime
  312. delete rechargeUser.value.endTime
  313. delete sortField.value
  314. delete sortOrder.value
  315. getTime.value = {}
  316. activeTimeRange.value = '' // 清除激活状态
  317. get()
  318. }
  319. // 今天
  320. const getToday = function () {
  321. const today = dayjs()
  322. const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
  323. const endTime =today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
  324. getTime.value = [startTime, endTime]
  325. console.log('getTime', getTime.value)
  326. activeTimeRange.value = 'today' // 标记当前激活状态
  327. get()
  328. }
  329. const handlePageSizeChange = function (val) {
  330. getObj.value.pageSize = val
  331. get()
  332. }
  333. const handleCurrentChange = function (val) {
  334. getObj.value.pageNum = val
  335. get()
  336. }
  337. // 昨天
  338. const getYesterday = function () {
  339. const today = dayjs()
  340. const startTime = today.subtract(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
  341. const endTime = today.subtract(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss')
  342. getTime.value = [startTime, endTime]
  343. console.log('getTime', getTime.value)
  344. activeTimeRange.value = 'yesterday' // 标记当前激活状态
  345. get()
  346. }
  347. // 近7天
  348. const get7Days = function () {
  349. const today = dayjs()
  350. const startTime = today.subtract(6, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
  351. const endTime = today.add(1, 'day').endOf('day').format('YYYY-MM-DD HH:mm:ss')
  352. getTime.value = [startTime, endTime]
  353. console.log('getTime', getTime.value)
  354. activeTimeRange.value = '7days' // 标记当前激活状态
  355. get()
  356. }
  357. // 挂载
  358. onMounted(async function () {
  359. await get()
  360. await getActivity()
  361. await getAdminData()
  362. await getArea()
  363. await getPlatform()
  364. })
  365. // 新增排序字段和排序方式
  366. const sortField = ref()
  367. const sortOrder = ref(1)
  368. // 处理排序事件
  369. const handleSortChange = (column) => {
  370. console.log('排序字段:', column.prop)
  371. console.log('排序方式:', column.order)
  372. if (column.prop === 'money') {
  373. sortField.value = 'money'
  374. } else if (column.prop === 'freeGold') {
  375. sortField.value = 'freeGold'
  376. } else if (column.prop === 'payTime') {
  377. sortField.value = 'payTime'
  378. } else if (column.prop === 'createTime') {
  379. sortField.value = 'createTime'
  380. } else if (column.prop === 'permanentGold') {
  381. sortField.value = 'permanentGold'
  382. }
  383. sortOrder.value = column.order === 'ascending' ? 'ASC' : 'DESC'
  384. console.log('传递给后端的排序字段:', sortField.value)
  385. console.log('传递给后端的排序方式:', sortOrder.value)
  386. get()
  387. }
  388. const exportExcel = async function () {
  389. const params = {
  390. rechargeUser: {
  391. jwcode: rechargeUser.value.jwcode || '',
  392. market: rechargeUser.value.market || '',
  393. payPlatform: rechargeUser.value.payPlatform || '',
  394. activity: rechargeUser.value.activity || '',
  395. startTime: rechargeUser.value.startTime || '',
  396. endTime: rechargeUser.value.endTime || ''
  397. },
  398. page: getObj.value.pageNum,
  399. size: total.value
  400. }
  401. try {
  402. const res = await API({url: '/export/exportRecharge', data: params})
  403. if (res.code === 200) {
  404. ElMessage.success('导出成功')
  405. } else {
  406. ElMessage.error(res.message || '导出失败,请稍后重试')
  407. }
  408. } catch (error) {
  409. console.log('请求失败', error)
  410. ElMessage.error('导出失败,请稍后重试')
  411. }
  412. }
  413. const exportListVisible = ref(false)
  414. // 打开导出列表弹窗
  415. const openExportList = () => {
  416. getExportList()
  417. exportListVisible.value = true
  418. }
  419. // 导出列表数据
  420. const exportList = ref([])
  421. // 导出列表加载状态
  422. const exportListLoading = ref(false)
  423. // 获取导出列表
  424. const getExportList = async () => {
  425. exportListLoading.value = true
  426. try {
  427. const result = await API({url: '/export/export'})
  428. if (result.code === 200) {
  429. const filteredData = result.data.filter(item => {
  430. return item.type === 2; //2表示金币充值列表
  431. });
  432. exportList.value = filteredData
  433. } else {
  434. ElMessage.error(result.msg || '获取导出列表失败')
  435. }
  436. } catch (error) {
  437. console.error('获取导出列表出错:', error)
  438. ElMessage.error('获取导出列表失败,请稍后重试')
  439. } finally {
  440. exportListLoading.value = false
  441. }
  442. }
  443. // 下载导出文件
  444. const downloadExportFile = (item) => {
  445. if (item.state === 2) {
  446. const link = document.createElement('a')
  447. link.href = item.url
  448. link.download = item.fileName
  449. link.click()
  450. } else {
  451. ElMessage.warning('文件还在导出中,请稍后再试')
  452. }
  453. }
  454. //根据状态返回对应的标签类型
  455. const getTagType = (state) => {
  456. switch (state) {
  457. case 0:
  458. return 'info';
  459. case 1:
  460. return 'primary';
  461. case 2:
  462. return 'success';
  463. case 3:
  464. return 'danger';
  465. default:
  466. return 'info';
  467. }
  468. }
  469. //根据状态返回对应的标签文案
  470. const getTagText = (state) => {
  471. switch (state) {
  472. case 0:
  473. return '待执行';
  474. case 1:
  475. return '执行中';
  476. case 2:
  477. return '执行完成';
  478. case 3:
  479. return '执行出错';
  480. default:
  481. return '未知状态';
  482. }
  483. }
  484. const props = {multiple: true}
  485. </script>
  486. <template>
  487. <el-row>
  488. <el-col>
  489. <el-card style="margin-bottom: 20px;margin-top: 10px">
  490. <el-row style="margin-bottom: 10px">
  491. <el-col :span="5">
  492. <div class="head-card-element">
  493. <el-text class="mx-1" size="large">精网号</el-text>
  494. <el-input v-model="rechargeUser.jwcode" placeholder="请输入精网号" style="width: 150px" clearable/>
  495. </div>
  496. </el-col>
  497. <el-col :span="6">
  498. <div class="head-card-element">
  499. <el-text class="mx-1" size="large">活动名称</el-text>
  500. <el-select v-model="rechargeUser.activity" placeholder="请选择活动名称" style="width: 180px" clearable>
  501. <el-option v-for="item in activity" :key="item.value" :label="item.label" :value="item.value"/>
  502. </el-select>
  503. </div>
  504. </el-col>
  505. <!-- <el-col :span="6">
  506. <div class="head-card-element">
  507. <el-text class="mx-1" size="large">所属地区</el-text>
  508. <el-select v-model="rechargeUser.market" placeholder="请选择所属地区" style="width: 180px" clearable>
  509. <el-option v-for="item in market" :key="item" :label="item" :value="item"/>
  510. </el-select>
  511. </div>
  512. </el-col> -->
  513. <el-col :span="6">
  514. <div class="head-card-element">
  515. <el-text class="mx-1" size="large">所属地区</el-text>
  516. <el-cascader
  517. v-model="selectedMarketPath"
  518. :options="markets"
  519. placeholder="请选择所属地区"
  520. clearable
  521. collapse-tags
  522. collapse-tags-tooltip
  523. style="width:180px"
  524. @change="handleMarketChange"
  525. :props="props"
  526. />
  527. </div>
  528. </el-col>
  529. <el-col :span="6">
  530. <div class="head-card-element">
  531. <el-text class="mx-1" size="large">充值方式</el-text>
  532. <el-select v-model="rechargeUser.payPlatform" placeholder="请选择充值方式" style="width: 180px" clearable>
  533. <el-option v-for="item in platform" :key="item.value" :label="item.label" :value="item.value"/>
  534. </el-select>
  535. </div>
  536. </el-col>
  537. </el-row>
  538. <el-row>
  539. <el-col :span="24">
  540. <div class="head-card-element">
  541. <el-text class="mx-1" size="large">充值时间</el-text>
  542. <el-date-picker v-model="getTime" type="datetimerange" range-separator="" start-placeholder="起始时间"
  543. end-placeholder="结束时间" style="width: 400px" @change="handleDatePickerChange" :default-time="defaultTime"/>
  544. <el-button @click="getToday()" style="margin-left: 10px"
  545. :type="activeTimeRange === 'today' ? 'primary' : ''">
  546. </el-button>
  547. <el-button @click="getYesterday()" style="margin-left: 10px"
  548. :type="activeTimeRange === 'yesterday' ? 'primary' : ''">
  549. </el-button>
  550. <el-button @click="get7Days()" style="margin-left: 10px"
  551. :type="activeTimeRange === '7days' ? 'primary' : ''"> 近7天
  552. </el-button>
  553. <el-button type="success" @click="reset()">重置</el-button>
  554. <el-button type="primary" @click="search()">查询</el-button>
  555. <el-button type="primary" @click="exportExcel()">导出Excel</el-button>
  556. <el-button type="primary" @click="openExportList">查看导出列表</el-button>
  557. </div>
  558. </el-col>
  559. </el-row>
  560. </el-card>
  561. </el-col>
  562. </el-row>
  563. <el-row>
  564. <el-col>
  565. <el-card>
  566. <div>
  567. 充值金额{{ (permanentGolds) / 100 }}新币永久金币{{
  568. permanentGolds / 100
  569. }}金币免费金币{{ freeGolds / 100 }}金币
  570. </div>
  571. <!-- 设置表格容器的高度和滚动样式 -->
  572. <div style="height: 520px; overflow-y: auto;margin-top: 10px;">
  573. <el-table :data="tableData" style="width: 100%" height="520px" @sort-change="handleSortChange">
  574. <el-table-column type="index" label="序号" width="80px" fixed="left">
  575. <template #default="scope">
  576. <span>{{
  577. scope.$index + 1 + (getObj.pageNum - 1) * getObj.pageSize
  578. }}</span>
  579. </template>
  580. </el-table-column>
  581. <el-table-column fixed="left" prop="name" label="姓名" width="150px"/>
  582. <el-table-column fixed="left" prop="jwcode" label="精网号" width="110px"/>
  583. <el-table-column prop="market" label="所属地区" width="100px">
  584. <template #default="scope">
  585. <span>{{ marketMapping[scope.row.market] || scope.row.market }}</span>
  586. </template>
  587. </el-table-column>
  588. <el-table-column prop="activity" label="活动名称" width="110px" show-overflow-tooltip/>
  589. <el-table-column prop="rateName" label="货币名称" width="110px"/>
  590. <el-table-column prop="money" sortable="custom" label="充值金额" width="110px"/>
  591. <el-table-column prop="permanentGold" label="永久金币" sortable="custom" width="110px"/>
  592. <el-table-column prop="freeGold" label="免费金币" sortable="custom" width="110px"/>
  593. <el-table-column prop="payPlatform" label="充值方式" width="100px"/>
  594. <el-table-column prop="payModel" label="支付方式" width="100px"/>
  595. <el-table-column prop="remark" label="备注" width="150px" show-overflow-tooltip/>
  596. <el-table-column prop="adminName" label="提交人" width="100px"/>
  597. <el-table-column prop="payTime" sortable label="充值时间" width="200px">
  598. <template #default="scope">
  599. {{ moment(scope.row.payTime).format('YYYY-MM-DD HH:mm:ss') }}
  600. </template>
  601. </el-table-column>
  602. </el-table>
  603. </div>
  604. <!-- 分页 -->
  605. <div class="pagination" style="margin-top: 20px">
  606. <el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
  607. layout="total, sizes, prev, pager, next, jumper" :total="total"
  608. @size-change="handlePageSizeChange"
  609. @current-change="handleCurrentChange"></el-pagination>
  610. </div>
  611. </el-card>
  612. </el-col>
  613. </el-row>
  614. <!-- 导出弹窗 -->
  615. <el-dialog v-model="exportListVisible" title="导出列表" width="80%">
  616. <el-table :data="exportList" style="width: 100% ;height: 60vh;" :loading="exportListLoading">
  617. <el-table-column prop="fileName" label="文件名"/>
  618. <el-table-column prop="state" label="状态">
  619. <template #default="scope">
  620. <el-tag :type="getTagType(scope.row.state)"
  621. :effect="scope.row.state === 3 ? 'light' : 'plain'">
  622. {{ getTagText(scope.row.state) }}
  623. </el-tag>
  624. </template>
  625. </el-table-column>
  626. <el-table-column prop="createTime" label="创建时间">
  627. <template #default="scope">
  628. {{ moment(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }}
  629. </template>
  630. </el-table-column>
  631. <el-table-column label="操作">
  632. <template #default="scope">
  633. <el-button type="primary" size="small" @click="downloadExportFile(scope.row)"
  634. :disabled="scope.row.state !== 2">
  635. 下载
  636. </el-button>
  637. </template>
  638. </el-table-column>
  639. </el-table>
  640. <template #footer>
  641. <div class="dialog-footer">
  642. <el-button text @click="exportListVisible = false">关闭</el-button>
  643. </div>
  644. </template>
  645. </el-dialog>
  646. </template>
  647. <style scoped>
  648. .pagination {
  649. display: flex;
  650. }
  651. .status {
  652. display: flex;
  653. }
  654. .head-card {
  655. display: flex;
  656. }
  657. .head-card-element {
  658. margin-right: 20px;
  659. }
  660. .head-card-btn {
  661. margin-left: auto;
  662. }
  663. </style>