formEditor.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <template>
  2. <ContentWrap>
  3. <!-- 表单设计器 -->
  4. <fc-designer ref="designer" height="780px">
  5. <template #handle>
  6. <XButton type="primary" title="生成JSON" @click="showJson" />
  7. <XButton type="primary" title="生成Options" @click="showOption" />
  8. <XButton type="primary" :title="t('action.save')" @click="handleSave" />
  9. </template>
  10. </fc-designer>
  11. <Dialog :title="dialogTitle" v-model="dialogVisible1" maxHeight="600">
  12. <div ref="editor" v-if="dialogVisible1">
  13. <XTextButton style="float: right" :title="t('common.copy')" @click="copy(formValue)" />
  14. <el-scrollbar height="580">
  15. <div v-highlight>
  16. <code class="hljs">
  17. {{ formValue }}
  18. </code>
  19. </div>
  20. </el-scrollbar>
  21. </div>
  22. </Dialog>
  23. <!-- 表单保存的弹窗 -->
  24. <XModal v-model="dialogVisible" title="保存表单">
  25. <el-form ref="formRef" :model="formValues" :rules="formRules" label-width="80px">
  26. <el-form-item label="表单名" prop="name">
  27. <el-input v-model="formValues.name" placeholder="请输入表单名" />
  28. </el-form-item>
  29. <el-form-item label="开启状态" prop="status">
  30. <el-radio-group v-model="formValues.status">
  31. <el-radio
  32. v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
  33. :key="dict.value"
  34. :label="dict.value"
  35. >
  36. {{ dict.label }}
  37. </el-radio>
  38. </el-radio-group>
  39. </el-form-item>
  40. <el-form-item label="备注" prop="remark">
  41. <el-input v-model="formValues.remark" type="textarea" placeholder="请输入备注" />
  42. </el-form-item>
  43. </el-form>
  44. <!-- 操作按钮 -->
  45. <template #footer>
  46. <!-- 按钮:保存 -->
  47. <XButton
  48. type="primary"
  49. :title="t('action.save')"
  50. :loading="dialogLoading"
  51. @click="submitForm"
  52. />
  53. <!-- 按钮:关闭 -->
  54. <XButton :title="t('dialog.close')" @click="dialogVisible = false" />
  55. </template>
  56. </XModal>
  57. </ContentWrap>
  58. </template>
  59. <script setup lang="ts" name="BpmFormEditor">
  60. import { FormInstance } from 'element-plus'
  61. import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
  62. import { CommonStatusEnum } from '@/utils/constants'
  63. import * as FormApi from '@/api/bpm/form'
  64. import { encodeConf, encodeFields, setConfAndFields } from '@/utils/formCreate'
  65. import { useClipboard } from '@vueuse/core'
  66. const { t } = useI18n() // 国际化
  67. const message = useMessage() // 消息
  68. const { query } = useRoute() // 路由
  69. const designer = ref() // 表单设计器
  70. const type = ref(-1)
  71. const formValue = ref('')
  72. const dialogTitle = ref('')
  73. const dialogVisible = ref(false) // 弹窗是否展示
  74. const dialogVisible1 = ref(false) // 弹窗是否展示
  75. const dialogLoading = ref(false) // 弹窗的加载中
  76. const formRef = ref<FormInstance>()
  77. const formRules = reactive({
  78. name: [{ required: true, message: '表单名不能为空', trigger: 'blur' }],
  79. status: [{ required: true, message: '开启状态不能为空', trigger: 'blur' }]
  80. })
  81. const formValues = ref({
  82. name: '',
  83. status: CommonStatusEnum.ENABLE,
  84. remark: ''
  85. })
  86. // 处理保存按钮
  87. const handleSave = () => {
  88. dialogVisible.value = true
  89. }
  90. // 提交保存表单
  91. const submitForm = async () => {
  92. // 参数校验
  93. const elForm = unref(formRef)
  94. if (!elForm) return
  95. const valid = await elForm.validate()
  96. if (!valid) return
  97. // 提交请求
  98. dialogLoading.value = true
  99. try {
  100. const data = formValues.value as FormApi.FormVO
  101. data.conf = encodeConf(designer) // 表单配置
  102. data.fields = encodeFields(designer) // 表单字段
  103. if (!data.id) {
  104. await FormApi.createFormApi(data)
  105. message.success(t('common.createSuccess'))
  106. } else {
  107. await FormApi.updateFormApi(data)
  108. message.success(t('common.updateSuccess'))
  109. }
  110. dialogVisible.value = false
  111. } finally {
  112. dialogLoading.value = false
  113. }
  114. }
  115. const showJson = () => {
  116. openModel('生成JSON')
  117. type.value = 0
  118. formValue.value = designer.value.getRule()
  119. }
  120. const showOption = () => {
  121. openModel('生成Options')
  122. type.value = 1
  123. formValue.value = designer.value.getOption()
  124. }
  125. const openModel = (title: string) => {
  126. dialogVisible1.value = true
  127. dialogTitle.value = title
  128. }
  129. /** 复制 **/
  130. const copy = async (text: string) => {
  131. const { copy, copied, isSupported } = useClipboard({ source: text })
  132. if (!isSupported) {
  133. message.error(t('common.copyError'))
  134. } else {
  135. await copy()
  136. if (unref(copied)) {
  137. message.success(t('common.copySuccess'))
  138. }
  139. }
  140. }
  141. // ========== 初始化 ==========
  142. onMounted(() => {
  143. // 场景一:新增表单
  144. const id = query.id as unknown as number
  145. if (!id) {
  146. return
  147. }
  148. // 场景二:修改表单
  149. FormApi.getFormApi(id).then((data) => {
  150. formValues.value = data
  151. setConfAndFields(designer, data.conf, data.fields)
  152. })
  153. })
  154. </script>