index.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <template>
  2. <!-- 搜索工作栏 -->
  3. <ContentWrap>
  4. <el-form
  5. ref="queryFormRef"
  6. :inline="true"
  7. :model="queryParams"
  8. class="-mb-15px"
  9. label-width="68px"
  10. >
  11. <el-form-item label="流程名称" prop="flowName">
  12. <el-input
  13. v-model="queryParams.flowName"
  14. class="!w-240px"
  15. clearable
  16. placeholder="请输入流程名称"
  17. @keyup.enter="handleQuery"
  18. />
  19. </el-form-item>
  20. <el-form-item>
  21. <el-button @click="handleQuery">
  22. <Icon class="mr-5px" icon="ep:search" />
  23. 搜索
  24. </el-button>
  25. <el-button @click="resetQuery">
  26. <Icon class="mr-5px" icon="ep:refresh" />
  27. 重置
  28. </el-button>
  29. <el-button plain type="primary" @click="openForm('create')">
  30. <Icon class="mr-5px" icon="ep:plus" />
  31. 新增
  32. </el-button>
  33. </el-form-item>
  34. </el-form>
  35. </ContentWrap>
  36. <!-- 列表 -->
  37. <ContentWrap>
  38. <el-table v-loading="loading" :data="list" style="width: 100%">
  39. <el-table-column label="流程名称" align="center" prop="flowName" min-width="120" />
  40. <el-table-column label="流程类型" align="center" min-width="90">
  41. <template #default="scope">
  42. {{
  43. getStrDictOptions(DICT_TYPE.FLOW_TYPE).find((dict) => dict.value === scope.row.type)
  44. ?.label || '-'
  45. }}
  46. </template>
  47. </el-table-column>
  48. <el-table-column
  49. label="流程链接"
  50. align="center"
  51. prop="flowUrl"
  52. min-width="120"
  53. show-overflow-tooltip
  54. />
  55. <el-table-column label="状态" align="center" prop="status" width="100">
  56. <template #default="scope">
  57. <el-tag :type="scope.row.status === 0 ? 'success' : 'danger'">
  58. {{ scope.row.status === 0 ? '正常' : '停用' }}
  59. </el-tag>
  60. </template>
  61. </el-table-column>
  62. <el-table-column label="排序" align="center" prop="sort" width="80" />
  63. <el-table-column
  64. label="备注"
  65. align="center"
  66. prop="remark"
  67. show-overflow-tooltip
  68. min-width="150"
  69. />
  70. <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  71. <template #default="scope">
  72. {{ formatDate(scope.row.createTime) }}
  73. </template>
  74. </el-table-column>
  75. <el-table-column label="操作" align="center" width="150" fixed="right">
  76. <template #default="scope">
  77. <el-button link type="primary" @click="openForm('update', scope.row)"> 编辑 </el-button>
  78. <el-button link type="danger" @click="handleDelete(scope.row.id)"> 删除 </el-button>
  79. </template>
  80. </el-table-column>
  81. </el-table>
  82. <!-- 分页 -->
  83. <Pagination
  84. :total="total"
  85. v-model:page="queryParams.pageNo"
  86. v-model:limit="queryParams.pageSize"
  87. @pagination="getList"
  88. />
  89. </ContentWrap>
  90. <!-- 表单弹窗:添加/修改 -->
  91. <el-dialog
  92. v-model="dialogVisible"
  93. :title="dialogTitle"
  94. width="500px"
  95. append-to-body
  96. @closed="handleDialogClosed"
  97. >
  98. <el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px">
  99. <el-form-item label="所属分组" prop="groupId">
  100. <el-select v-model="formData.groupId" placeholder="请选择所属分组" class="w-full">
  101. <el-option
  102. v-for="group in groupList"
  103. :key="group.id"
  104. :label="group.groupName"
  105. :value="group.id"
  106. />
  107. </el-select>
  108. </el-form-item>
  109. <el-form-item label="流程类型" prop="type">
  110. <el-select v-model="formData.type" placeholder="请选择流程类型" clearable>
  111. <el-option
  112. v-for="dict in getStrDictOptions(DICT_TYPE.FLOW_TYPE)"
  113. :key="dict.value"
  114. :label="dict.label"
  115. :value="dict.value"
  116. />
  117. </el-select>
  118. </el-form-item>
  119. <el-form-item label="流程名称" prop="flowName">
  120. <!-- <el-input v-model="formData.flowName" placeholder="请输入流程名称" /> -->
  121. <lang-input v-model="formData.flowName" placeholder="请输入流程名称" />
  122. </el-form-item>
  123. <el-form-item label="排序" prop="sort">
  124. <el-input-number
  125. v-model="formData.sort"
  126. :min="0"
  127. controls-position="right"
  128. class="!w-100%"
  129. />
  130. </el-form-item>
  131. <el-form-item label="菜单图标">
  132. <IconSelect v-model="formData.icon" clearable />
  133. </el-form-item>
  134. <el-form-item label="首页地址" prop="indexUrl">
  135. <el-input v-model="formData.indexUrl" placeholder="请输入首页地址" />
  136. </el-form-item>
  137. <el-form-item label="流程链接" prop="flowUrl">
  138. <el-input v-model="formData.flowUrl" placeholder="请输入流程链接" />
  139. </el-form-item>
  140. <el-form-item label="App流程链接" prop="appUrl">
  141. <el-input v-model="formData.appUrl" placeholder="请输入App流程链接" />
  142. </el-form-item>
  143. <el-form-item label="状态" prop="status">
  144. <el-radio-group v-model="formData.status">
  145. <el-radio :value="0">正常</el-radio>
  146. <el-radio :value="1">停用</el-radio>
  147. </el-radio-group>
  148. </el-form-item>
  149. <el-form-item label="备注" prop="remark">
  150. <el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
  151. </el-form-item>
  152. </el-form>
  153. <template #footer>
  154. <el-button @click="dialogVisible = false">取 消</el-button>
  155. <el-button type="primary" @click="submitForm" :loading="submitLoading"> 确 定 </el-button>
  156. </template>
  157. </el-dialog>
  158. </template>
  159. <script setup>
  160. import { ref, reactive, onMounted } from 'vue'
  161. import { ElMessage, ElMessageBox } from 'element-plus'
  162. import { Icon } from '@/components/Icon'
  163. import Pagination from '@/components/Pagination/index.vue'
  164. import { formatDate } from '@/utils/formatTime'
  165. import { createFlow, getFlowList, updateFlow, deleteFlow, getGroupList } from '@/api/flow'
  166. import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
  167. // --- 响应式数据 ---
  168. const loading = ref(false)
  169. const list = ref([])
  170. const total = ref(0)
  171. const groupList = ref([])
  172. const queryParams = reactive({
  173. pageNo: 1,
  174. pageSize: 10,
  175. flowName: undefined
  176. })
  177. const queryFormRef = ref(null)
  178. // 表单相关
  179. const dialogVisible = ref(false)
  180. const dialogTitle = ref('')
  181. const formRef = ref(null)
  182. const submitLoading = ref(false)
  183. const formData = reactive({
  184. id: undefined,
  185. groupId: undefined,
  186. flowName: '',
  187. flowUrl: '',
  188. appUrl: '',
  189. remark: '',
  190. status: 0, // 默认正常,
  191. indexUrl: '', // 前端路由地址,后端不存储,仅供前端使用
  192. sort: 0,
  193. type: undefined // 流程类型
  194. })
  195. const formRules = reactive({
  196. groupId: [{ required: true, message: '请选择所属分组', trigger: 'change' }],
  197. flowName: [{ required: true, message: '请输入流程名称', trigger: 'blur' }],
  198. sort: [{ required: true, message: '请输入排序', trigger: 'blur' }],
  199. flowUrl: [{ required: true, message: '请输入流程链接', trigger: 'blur' }],
  200. // appUrl: [{ required: true, message: '请输入App流程链接', trigger: 'blur' }],
  201. status: [{ required: true, message: '请选择状态', trigger: 'change' }],
  202. indexUrl: [{ required: true, message: '请输入首页地址', trigger: 'blur' }],
  203. type: [{ required: true, message: '请选择流程类型', trigger: 'change' }]
  204. })
  205. // --- 方法 ---
  206. const getList = async () => {
  207. loading.value = true
  208. try {
  209. const res = await getFlowList(queryParams)
  210. list.value = res.list
  211. total.value = res.total
  212. } catch (error) {
  213. console.error(error)
  214. } finally {
  215. loading.value = false
  216. }
  217. }
  218. const handleQuery = () => {
  219. queryParams.pageNo = 1
  220. getList()
  221. }
  222. const resetQuery = () => {
  223. queryFormRef.value?.resetFields()
  224. handleQuery()
  225. }
  226. const openForm = (type, row) => {
  227. dialogVisible.value = true
  228. dialogTitle.value = type === 'create' ? '新增流程' : '编辑流程'
  229. if (type === 'create') {
  230. formData.id = undefined
  231. formData.groupId = undefined
  232. formData.flowName = ''
  233. formData.indexUrl = ''
  234. formData.flowUrl = ''
  235. formData.appUrl = ''
  236. formData.remark = ''
  237. formData.status = 0 // 新增时默认正常
  238. formData.sort = 0 // 新增时默认排序为0
  239. formData.type = undefined
  240. } else {
  241. // 编辑模式:深拷贝,避免直接修改表格数据
  242. Object.assign(formData, JSON.parse(JSON.stringify(row)))
  243. // 确保 status 有值,防止后端返回 null 导致单选框异常
  244. if (formData.status === null || formData.status === undefined) {
  245. formData.status = 0
  246. }
  247. }
  248. // 清除校验状态
  249. formRef.value?.clearValidate()
  250. }
  251. // 对话框关闭时重置表单
  252. const handleDialogClosed = () => {
  253. formRef.value?.resetFields()
  254. }
  255. const submitForm = async () => {
  256. if (!formRef.value) return
  257. await formRef.value.validate(async (valid) => {
  258. if (valid) {
  259. submitLoading.value = true
  260. try {
  261. const submitData = { ...formData }
  262. if (formData.id) {
  263. await updateFlow(submitData)
  264. ElMessage.success('修改成功')
  265. } else {
  266. await createFlow(submitData)
  267. ElMessage.success('新增成功')
  268. }
  269. dialogVisible.value = false
  270. await getList()
  271. } catch (error) {
  272. console.error(error)
  273. } finally {
  274. submitLoading.value = false
  275. }
  276. }
  277. })
  278. }
  279. const handleDelete = async (id) => {
  280. try {
  281. await ElMessageBox.confirm('确定要删除该项吗?', '提示', {
  282. confirmButtonText: '确定',
  283. cancelButtonText: '取消',
  284. type: 'warning'
  285. })
  286. await deleteFlow(id)
  287. ElMessage.success('删除成功')
  288. await getList()
  289. } catch (error) {
  290. // ignore
  291. }
  292. }
  293. onMounted(async () => {
  294. getList()
  295. const res = await getGroupList()
  296. groupList.value = res.list || []
  297. })
  298. </script>
  299. <style scoped></style>