OrderForm.vue 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. <template>
  2. <div>
  3. <MForm ref="form" :items="formItems" v-model="formValues">
  4. <template #tips>
  5. <v-alert color="primary accent-4" elevation="1" colored-border border="left">
  6. <span style="color: #777; font-size: 14px;">
  7. 在需求描述框内点击鼠标右键,选择“插入业务域”,即可插入业务域。(提示:鼠标右键仅在需求描述框内有效,插入位置为光标所在位置)
  8. </span>
  9. </v-alert>
  10. </template>
  11. </MForm>
  12. <v-menu
  13. v-model="contextMenuVisible"
  14. attach
  15. :position-x="contextMenuX"
  16. :position-y="contextMenuY"
  17. absolute
  18. offset-y
  19. nudge-top="8"
  20. >
  21. <v-list dense>
  22. <v-list-item @click="handleInsertBusinessDomainClick">
  23. <v-list-item-title>插入业务域</v-list-item-title>
  24. </v-list-item>
  25. </v-list>
  26. </v-menu>
  27. <v-dialog v-model="insertDialogVisible" max-width="400" persistent>
  28. <v-card>
  29. <v-card-title>选择要插入的业务域</v-card-title>
  30. <v-card-text>
  31. <v-autocomplete
  32. v-model="insertDialogSelected"
  33. :items="businessDomain"
  34. item-text="name_zh"
  35. item-value="name_zh"
  36. label="请选择业务域"
  37. outlined
  38. dense
  39. hide-details
  40. clearable
  41. @change="handleInsertDialogSelect"
  42. />
  43. </v-card-text>
  44. <v-card-actions>
  45. <v-spacer />
  46. <v-btn text @click="insertDialogVisible = false">取消</v-btn>
  47. <v-btn color="primary" text @click="handleInsertDialogConfirm">插入</v-btn>
  48. </v-card-actions>
  49. </v-card>
  50. </v-dialog>
  51. </div>
  52. </template>
  53. <script>
  54. import MForm from '@/components/MForm'
  55. import { api } from '@/api/dataGovernance'
  56. import { getDatasourceList } from '@/api/dataOrigin'
  57. export default {
  58. name: 'CreateOrderDialog',
  59. components: {
  60. MForm
  61. },
  62. props: {
  63. itemData: {
  64. type: Object,
  65. default: () => {}
  66. }
  67. },
  68. data () {
  69. return {
  70. formValues: {
  71. title: '',
  72. description: '',
  73. data_source: '',
  74. created_by: this.$store.getters.userInfo?.username || '',
  75. extracted_domains: [],
  76. extracted_fields: [],
  77. extraction_purpose: ''
  78. },
  79. dataSourceItems: [],
  80. businessDomain: [],
  81. descriptionCursor: { start: 0, end: 0 },
  82. descriptionCursorTouched: false,
  83. contextMenuVisible: false,
  84. contextMenuX: 0,
  85. contextMenuY: 0,
  86. insertDialogVisible: false,
  87. insertDialogSelected: null
  88. }
  89. },
  90. computed: {
  91. formItems () {
  92. return [
  93. {
  94. type: 'text',
  95. key: 'title',
  96. label: '订单标题 *',
  97. placeholder: '请输入订单标题,例如:员工与部门关联数据',
  98. rules: [
  99. v => !!v || '请输入订单标题',
  100. v => (v && v.length <= 200) || '标题不能超过200个字符'
  101. ],
  102. maxlength: 200,
  103. counter: true,
  104. outlined: true,
  105. dense: true,
  106. hideDetails: 'auto'
  107. },
  108. {
  109. type: 'autocomplete',
  110. key: 'data_source',
  111. label: '请选择输出数据源',
  112. noAttach: true,
  113. itemText: 'name_zh',
  114. itemValue: 'id',
  115. items: this.dataSourceItems
  116. },
  117. {
  118. type: 'text',
  119. key: 'created_by',
  120. label: '创建人',
  121. outlined: true,
  122. dense: true
  123. },
  124. {
  125. type: 'textarea',
  126. key: 'description',
  127. label: '需求描述 *',
  128. placeholder: '请详细描述需要什么数据,包括: 1. 涉及的业务领域(如员工、部门、项目等) 2. 需要的具体字段 3. 数据用途',
  129. rules: [
  130. v => !!v || '请输入需求描述',
  131. v => (v && v.length >= 10) || '描述至少需要10个字符'
  132. ],
  133. maxlength: 2000,
  134. counter: true,
  135. outlined: true,
  136. rows: 8,
  137. hideDetails: 'auto',
  138. cursorRef: this.descriptionCursor,
  139. onCursorSync: () => { this.descriptionCursorTouched = true },
  140. onContextMenu: this.handleDescriptionContextMenu
  141. },
  142. {
  143. slotName: 'tips'
  144. }
  145. ]
  146. }
  147. },
  148. created () {
  149. this.init()
  150. this.getBusinessDomainList()
  151. if (this.itemData && this.itemData.id) {
  152. this.formValues = {
  153. title: this.itemData.title || '',
  154. description: this.itemData.description || '',
  155. data_source: this.itemData.data_source || '',
  156. extracted_domains: this.itemData.extracted_domains || [],
  157. extracted_fields: this.itemData.extracted_fields || [],
  158. extraction_purpose: this.itemData.extraction_purpose || ''
  159. }
  160. }
  161. },
  162. methods: {
  163. async init () {
  164. try {
  165. const { data } = await getDatasourceList({})
  166. this.dataSourceItems = data.data_source
  167. } catch (error) {
  168. this.$snackbar.error(error)
  169. }
  170. },
  171. // 获取业务域列表
  172. async getBusinessDomainList () {
  173. try {
  174. const { data } = await api.getBusinessDomainList2()
  175. if (!data || !data?.length) {
  176. this.businessDomain = []
  177. return
  178. }
  179. this.businessDomain = data
  180. } catch (error) {
  181. this.$snackbar.error(error)
  182. }
  183. },
  184. // 插入业务域
  185. handleDescriptionContextMenu (item, event) {
  186. if (!event) return
  187. const rect = this.$el.getBoundingClientRect()
  188. this.contextMenuX = event.clientX - rect.left
  189. this.contextMenuY = event.clientY - rect.top + 110
  190. this.contextMenuVisible = true
  191. },
  192. handleInsertBusinessDomainClick () {
  193. this.contextMenuVisible = false
  194. this.insertDialogSelected = null
  195. this.insertDialogVisible = true
  196. },
  197. handleInsertDialogSelect (val) {
  198. if (val != null && val !== '') {
  199. this.handleBusinessDomainInsert(val)
  200. this.insertDialogVisible = false
  201. this.insertDialogSelected = null
  202. }
  203. },
  204. handleInsertDialogConfirm () {
  205. if (this.insertDialogSelected != null && this.insertDialogSelected !== '') {
  206. this.handleBusinessDomainInsert(this.insertDialogSelected)
  207. }
  208. this.insertDialogVisible = false
  209. this.insertDialogSelected = null
  210. },
  211. handleBusinessDomainInsert (val) {
  212. const { start, end } = this.descriptionCursor
  213. const desc = this.formValues.description || ''
  214. const useAppend = !this.descriptionCursorTouched && desc.length > 0
  215. const insertStart = useAppend ? desc.length : start
  216. const insertEnd = useAppend ? desc.length : end
  217. this.formValues.description = desc.slice(0, insertStart) + val + desc.slice(insertEnd)
  218. this.descriptionCursor.start = this.descriptionCursor.end = insertStart + val.length
  219. },
  220. getValue () {
  221. if (!this.$refs.form.validate()) {
  222. return
  223. }
  224. const params = {
  225. title: this.formValues.title,
  226. description: this.formValues.description,
  227. created_by: this.formValues.created_by,
  228. data_source: this.formValues.data_source
  229. }
  230. return this.itemData.id ? this.formValues : params
  231. }
  232. }
  233. }
  234. </script>