index.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <template>
  2. <div class="white pa-3">
  3. <m-filter :option="filter" @search="handleSearch" />
  4. <m-table
  5. class="mt-3"
  6. :loading="loading"
  7. :headers="headers"
  8. :items="items"
  9. :total="total"
  10. :is-tools="false"
  11. :disable-sort="true"
  12. :page-info="pageInfo"
  13. :show-select="false"
  14. :can-delete="false"
  15. @pageHandleChange="pageHandleChange"
  16. >
  17. <template #record_type="{ item }">
  18. {{ item.record_type === 'redundancy' ? '疑似冗余' : '疑似变动' }}
  19. </template>
  20. <template #status="{ item }">
  21. <v-chip small :color="item.status === 'pending' ? 'warning' : item.status === 'resolved' ? 'success' : ''">
  22. {{ item.status === 'pending' ? '待处理' : item.status === 'resolved' ? '已处理' : '已忽略' }}
  23. </v-chip>
  24. </template>
  25. <template #created_at="{ item }">
  26. {{ formatDate(item.created_at) }}
  27. </template>
  28. <template #actions="{ item }">
  29. <v-btn color="success" text class="mr-2" @click="handleAction(item)">详情</v-btn>
  30. <v-btn v-if="item.status === 'pending'" color="primary" text @click="handleAction(item)">处理</v-btn>
  31. </template>
  32. </m-table>
  33. <edit-dialog :visible.sync="show" title="数据审核详情" fullscreen :footer="false">
  34. <!-- 疑似冗余 -->
  35. <redundancy-component
  36. v-if="info?.record_type === 'redundancy'"
  37. :info="info"
  38. @selectCandidateMeta="val => candidateMetaId = val"
  39. />
  40. <!-- 疑似变动 -->
  41. <change-component
  42. v-if="info?.record_type === 'change'"
  43. :info="info"
  44. />
  45. <template v-if="info?.status === 'pending'" #footer>
  46. <v-divider></v-divider>
  47. <v-card-actions>
  48. <v-spacer></v-spacer>
  49. <v-btn v-if="info?.record_type === 'redundancy'" text color="pink" class="mr-2" @click="handleSubmit(info, 'alias')">设为别名</v-btn>
  50. <v-btn v-if="info?.record_type === 'redundancy'" text color="primary" class="mr-2" @click="handleSubmit(info, 'create_new')">创建新元数据</v-btn>
  51. <v-btn v-if="info?.record_type === 'change'" text color="success" class="mr-2" @click="handleSubmit(info, 'accept_change')">接受变动</v-btn>
  52. <v-btn v-if="info?.record_type === 'change'" text color="error" class="mr-2" @click="handleSubmit(info, 'reject_change')">拒绝变动</v-btn>
  53. <v-btn text color="warning" @click="handleSubmit(info, 'ignore')">忽略</v-btn>
  54. </v-card-actions>
  55. </template>
  56. </edit-dialog>
  57. <!-- 创建新元数据 -->
  58. <edit-dialog :visible.sync="createNew.show" title="创建新元数据" @submit="handleCreateNew">
  59. <v-text-field
  60. v-model="createNew.name_zh"
  61. label="中文名称"
  62. outlined
  63. clearable
  64. dense
  65. hide-details
  66. placeholder="请输入元数据中文名称"
  67. />
  68. </edit-dialog>
  69. </div>
  70. </template>
  71. <script>
  72. import MFilter from '@/components/Filter'
  73. import MTable from '@/components/List/table.vue'
  74. import EditDialog from '@/components/Dialog'
  75. import RedundancyComponent from './components/redundancy.vue'
  76. import ChangeComponent from './components/change.vue'
  77. import { dataReviewList, dataReviewDetail, dataReviewResolve } from '@/api/dataDeduplication'
  78. import { api } from '@/api/dataGovernance'
  79. export default {
  80. name: 'dataProcess',
  81. components: {
  82. MFilter,
  83. MTable,
  84. EditDialog,
  85. RedundancyComponent,
  86. ChangeComponent
  87. },
  88. data () {
  89. return {
  90. show: false,
  91. loading: false,
  92. filter: {
  93. list: [
  94. {
  95. type: 'textField',
  96. value: '',
  97. label: '关键词',
  98. key: 'keyword'
  99. },
  100. {
  101. type: 'autocomplete',
  102. value: null,
  103. label: '业务域',
  104. itemValue: 'id',
  105. itemText: 'name_zh',
  106. key: 'business_domain_id',
  107. items: []
  108. },
  109. {
  110. type: 'autocomplete',
  111. value: null,
  112. label: '记录类型',
  113. key: 'record_type',
  114. items: [{ label: '疑似冗余', value: 'redundancy' }, { label: '疑似变动', value: 'change' }]
  115. },
  116. {
  117. type: 'autocomplete',
  118. value: 'pending',
  119. label: '状态',
  120. key: 'status',
  121. items: [{ label: '待处理', value: 'pending' }, { label: '已处理', value: 'resolved' }, { label: '已忽略', value: 'ignored' }]
  122. }
  123. ]
  124. },
  125. queryData: {
  126. keyword: null,
  127. status: 'pending',
  128. business_domain_id: null,
  129. record_type: null
  130. },
  131. headers: [
  132. { text: '中文名称', align: 'start', value: 'new_meta.name_zh' },
  133. { text: '英文名称', align: 'start', value: 'new_meta.name_en' },
  134. { text: '记录类型', align: 'center', value: 'record_type' },
  135. { text: '状态', align: 'center', value: 'status' },
  136. { text: '创建时间', align: 'start', value: 'created_at' },
  137. { text: '操作', align: 'start', value: 'actions' }
  138. ],
  139. items: [],
  140. pageInfo: {
  141. size: 10,
  142. current: 1
  143. },
  144. candidateMetaId: null,
  145. total: 0,
  146. info: {},
  147. createNew: {
  148. show: false,
  149. name_zh: null,
  150. params: {}
  151. }
  152. }
  153. },
  154. created () {
  155. this.getBusinessDomainList()
  156. this.init()
  157. },
  158. methods: {
  159. // 获取业务域列表
  160. async getBusinessDomainList () {
  161. try {
  162. const { data } = await api.getBusinessDomainList2()
  163. const businessDomain = this.filter.list.find(item => item.key === 'business_domain_id')
  164. if (!data || !data?.length) {
  165. businessDomain.items = []
  166. return
  167. }
  168. businessDomain.items = data
  169. } catch (error) {
  170. this.$snackbar.error(error)
  171. }
  172. },
  173. async init () {
  174. this.loading = true
  175. try {
  176. const { data } = await dataReviewList({
  177. ...this.pageInfo,
  178. ...this.queryData
  179. })
  180. this.items = data.records
  181. this.total = data.total
  182. } catch (error) {
  183. this.$snackbar.error(error)
  184. } finally {
  185. this.loading = false
  186. }
  187. },
  188. handleSearch (val) {
  189. Object.assign(this.queryData, val)
  190. this.pageInfo.current = 1
  191. this.init()
  192. },
  193. pageHandleChange (page) {
  194. this.pageInfo.current = page
  195. this.init()
  196. },
  197. // 详情、处理
  198. async handleAction (item) {
  199. try {
  200. const { data } = await dataReviewDetail(item.id)
  201. this.info = data || {}
  202. this.show = true
  203. } catch (error) {
  204. this.$snackbar.error(error)
  205. }
  206. },
  207. // 作为新元数据创建
  208. async handleCreateNew () {
  209. if (!this.createNew.name_zh) {
  210. this.$snackbar.warning('请输入元数据中文名称')
  211. return
  212. }
  213. this.createNew.params.payload = {
  214. new_name_zh: this.createNew.name_zh
  215. }
  216. try {
  217. await dataReviewResolve(this.createNew.params)
  218. this.$snackbar.success('操作成功')
  219. this.createNew.show = false
  220. this.show = false
  221. this.init()
  222. } catch (error) {
  223. this.$snackbar.error(error.message)
  224. } finally {
  225. this.createNew = {
  226. name_zh: null,
  227. params: {},
  228. show: false
  229. }
  230. }
  231. },
  232. // 设为别名、接受变动、拒绝变动、忽略
  233. async handleSubmit (item, action) {
  234. const params = {
  235. id: item.id,
  236. action: action,
  237. resolved_by: this.$store.getters.userInfo.username,
  238. notes: ''
  239. }
  240. // 作为新元数据创建
  241. if (action === 'create_new') {
  242. this.createNew = {
  243. show: true,
  244. name_zh: item.new_meta.name_zh,
  245. params
  246. }
  247. return
  248. }
  249. // 设为某候选元数据别名
  250. if (action === 'alias') {
  251. if (!this.candidateMetaId) {
  252. this.$snackbar.warning('请选择候选元数据')
  253. return
  254. }
  255. params.payload = {
  256. candidate_meta_id: this.candidateMetaId
  257. }
  258. } else if (action === 'accept_change') { // 接受变动
  259. params.payload = {
  260. meta_id: item?.old_meta?.meta_id
  261. }
  262. }
  263. try {
  264. await dataReviewResolve(params)
  265. this.$snackbar.success('操作成功')
  266. this.show = false
  267. this.init()
  268. } catch (error) {
  269. this.$snackbar.error(error)
  270. }
  271. },
  272. formatDate (date) {
  273. if (!date) return '-'
  274. const d = new Date(date)
  275. if (isNaN(d.getTime())) return date
  276. const year = d.getFullYear()
  277. const month = String(d.getMonth() + 1).padStart(2, '0')
  278. const day = String(d.getDate()).padStart(2, '0')
  279. const hours = String(d.getHours()).padStart(2, '0')
  280. const minutes = String(d.getMinutes()).padStart(2, '0')
  281. const seconds = String(d.getSeconds()).padStart(2, '0')
  282. return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
  283. }
  284. }
  285. }
  286. </script>
  287. <style lang="scss" scoped>
  288. </style>