index.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. <template>
  2. <div class="feedbackRecord">
  3. <Search :onClickSearch="onClickSearch" :onClickReset="onClickReset" />
  4. <div class="feedbackRecord-table">
  5. <a-table :scroll="{ x: '100%', y: 500 }" :childrenColumnName="null" rowKey="device_sn"
  6. :loading="state.listLoading" :columns="columns" @change="refreshData" :rowClassName="rowClassName"
  7. :dataSource="state.list" :pagination="paginationConfig">
  8. <!-- 设备型号 -->
  9. <template #device_name="{ record }">
  10. <CustomCell :record="record" fieldName="device_name" />
  11. </template>
  12. <!-- 设备SN -->
  13. <template #device_sn="{ record }">
  14. <CustomCell :record="record" fieldName="device_sn" />
  15. </template>
  16. <!-- 设备名称 -->
  17. <template #nick_name="{ record }">
  18. <CustomCell :record="record" fieldName="nick_name" />
  19. </template>
  20. <!-- 固件版本 -->
  21. <template #firmware_version="{ record }">
  22. <CustomCell :record="record" fieldName="firmware_version" />
  23. </template>
  24. <template #status="{ record }">
  25. 上传状态
  26. </template>
  27. <!-- 操作 -->
  28. <template #operation="{ record }">
  29. <div class="editable-row-operations">
  30. <div class="flex-align-center flex-row" style="color: #2d8cf0">
  31. <a-tooltip title="详情">
  32. <FileSearchOutlined style="margin-right: 10px;" @click="onClickDetail(record.id)" />
  33. </a-tooltip>
  34. <a-tooltip title="删除">
  35. <DeleteOutlined @click="onClickDelete(record.id)" />
  36. </a-tooltip>
  37. </div>
  38. </div>
  39. </template>
  40. </a-table>
  41. </div>
  42. <Drawer :id="state.currentId" :visible="state.drawerVisible" :onClose="drawerOnClickClose" />
  43. </div>
  44. </template>
  45. <script lang="ts" setup>
  46. import { reactive, onMounted } from 'vue';
  47. import { Modal } from 'ant-design-vue';
  48. import { DeleteOutlined, FileSearchOutlined } from '@ant-design/icons-vue';
  49. import Search from './components/Search.vue';
  50. import CustomCell from './components/CustomCell.vue';
  51. import Drawer from './components/Drawer.vue';
  52. import { apis } from '/@/api/custom/index';
  53. interface State {
  54. query: any,
  55. listLoading: boolean,
  56. list: any[],
  57. currentId: string,
  58. drawerVisible: boolean,
  59. };
  60. const state: State = reactive({
  61. query: undefined,
  62. listLoading: false,
  63. list: [],
  64. currentId: '',
  65. drawerVisible: false,
  66. });
  67. const paginationConfig = reactive({
  68. pageSizeOptions: ['20', '50', '100'],
  69. showQuickJumper: true,
  70. showSizeChanger: true,
  71. pageSize: 20,
  72. current: 1,
  73. total: 0
  74. })
  75. const fetchList = async () => {
  76. state.listLoading = true;
  77. try {
  78. const res = await apis.fetchChangeRecordList({
  79. ...state.query,
  80. page: paginationConfig.current,
  81. page_size: paginationConfig.pageSize
  82. });
  83. if (res.code === 0) {
  84. paginationConfig.total = res.data.pagination.total
  85. paginationConfig.current = res.data.pagination.page
  86. paginationConfig.pageSize = res.data.pagination.page_size
  87. }
  88. state.list = res.data.list;
  89. } catch (e) {
  90. console.error(e);
  91. } finally {
  92. state.listLoading = false;
  93. }
  94. }
  95. onMounted(async () => {
  96. await fetchList();
  97. })
  98. const columns = [
  99. {
  100. title: '反馈时间',
  101. dataIndex: 'create_time',
  102. width: 200,
  103. sorter: (a: any, b: any) => a.create_time.localeCompare(b.create_time),
  104. },
  105. {
  106. title: '反馈人',
  107. dataIndex: 'username',
  108. width: 150,
  109. },
  110. {
  111. title: '设备型号',
  112. dataIndex: 'device_name',
  113. width: 150,
  114. sorter: (a: any, b: any) => a.device_name.localeCompare(b.device_name),
  115. slots: { customRender: 'device_name' }
  116. },
  117. {
  118. title: '设备SN',
  119. dataIndex: 'device_sn',
  120. width: 250,
  121. slots: { customRender: 'device_sn' }
  122. },
  123. {
  124. title: '设备名称',
  125. dataIndex: 'nick_name',
  126. width: 150,
  127. slots: { customRender: 'nick_name' },
  128. sorter: (a: any, b: any) => a.nick_name.localeCompare(b.nick_name),
  129. },
  130. {
  131. title: '固件版本',
  132. dataIndex: 'firmware_version',
  133. width: 150,
  134. ellipsis: true,
  135. slots: { customRender: 'firmware_version' }
  136. },
  137. {
  138. title: '设备异常描述',
  139. dataIndex: 'log_info',
  140. width: 150,
  141. ellipsis: true,
  142. },
  143. {
  144. title: '上传状态',
  145. dataIndex: 'status',
  146. slots: { customRender: 'status' },
  147. sorter: (a: any, b: any) => a.status.localeCompare(b.status),
  148. width: 150,
  149. },
  150. {
  151. title: '操作',
  152. dataIndex: 'operation',
  153. fixed: 'right',
  154. width: 80,
  155. slots: { customRender: 'operation' }
  156. },
  157. ]
  158. const rowClassName = (record: any, index: number) => {
  159. const className = []
  160. if ((index & 1) === 0) {
  161. className.push('table-striped')
  162. }
  163. return className.toString().replaceAll(',', ' ')
  164. }
  165. const refreshData = async (page: any) => {
  166. paginationConfig.current = page?.current!
  167. paginationConfig.pageSize = page?.pageSize!
  168. await fetchList();
  169. }
  170. // 点击搜索
  171. const onClickSearch = async (query: any) => {
  172. state.query = query;
  173. await fetchList();
  174. }
  175. // 点击重置
  176. const onClickReset = async (query: any) => {
  177. state.query = query;
  178. await fetchList();
  179. }
  180. // 点击详情
  181. const onClickDetail = (id: string) => {
  182. state.currentId = id;
  183. state.drawerVisible = true;
  184. }
  185. const drawerOnClickClose = () => {
  186. state.drawerVisible = false;
  187. }
  188. // 点击删除
  189. const onClickDelete = (id: number) => {
  190. Modal.confirm({
  191. title: '提示',
  192. content: '确定删除吗?',
  193. onOk: async () => {
  194. },
  195. });
  196. }
  197. </script>
  198. <style lang="scss">
  199. .feedbackRecord {
  200. padding: 20px;
  201. }
  202. .ant-table {
  203. border-top: 1px solid rgb(0, 0, 0, 0.06);
  204. border-bottom: 1px solid rgb(0, 0, 0, 0.06);
  205. }
  206. .ant-table-tbody tr td {
  207. border: 0;
  208. }
  209. </style>