DatabaseSetter.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <!--
  2. * @Author: liuJie
  3. * @Date: 2026-01-25 22:08:04
  4. * @LastEditors: liuJie
  5. * @LastEditTime: 2026-01-25 23:05:13
  6. * @Describe: 数据设置器
  7. -->
  8. <script lang="ts" setup>
  9. import { computed, ref, watch } from 'vue'
  10. import { IconButton, Icon } from '@repo/ui'
  11. import SelectTableModal from '@/features/selectTableModal/index.vue'
  12. import { clone, isEqual } from 'lodash-es'
  13. const props = withDefaults(
  14. defineProps<{
  15. data: any
  16. }>(),
  17. {
  18. data: {}
  19. }
  20. )
  21. const emit = defineEmits<{
  22. update: [data: unknown]
  23. }>()
  24. const DEFAULT_DATA = {
  25. tableList: [],
  26. fieldList: [],
  27. limit: 100,
  28. sortList: [],
  29. conditionList: [],
  30. output: {
  31. outputList: []
  32. },
  33. exception: 'none',
  34. exceptionDefaultValue: {
  35. body: '',
  36. status_code: 0,
  37. headers: '{}'
  38. }
  39. }
  40. const formData = ref(clone(DEFAULT_DATA))
  41. watch(
  42. () => props.data,
  43. (newVal) => {
  44. if (!isEqual(newVal, formData.value)) {
  45. formData.value = {
  46. ...clone(DEFAULT_DATA),
  47. ...(newVal || {})
  48. }
  49. }
  50. },
  51. {
  52. deep: true,
  53. immediate: true
  54. }
  55. )
  56. watch(
  57. () => formData.value,
  58. (value) => {
  59. emit('update', value)
  60. },
  61. { deep: true }
  62. )
  63. const selectTableModalRef = ref<InstanceType<typeof SelectTableModal> | null>(null)
  64. const exceptionOptions = [
  65. { label: '无', value: 'none' },
  66. { label: '默认值', value: 'default_value' },
  67. { label: '异常分支', value: 'exception_branch' }
  68. ]
  69. const columns = computed(() => {
  70. return (formData.value.tableList?.[0]?.columns || []).filter(
  71. (item: any) => !formData.value.fieldList.find((field: any) => field.name === item.name)
  72. )
  73. })
  74. const addDatabase = () => {
  75. selectTableModalRef.value?.open()
  76. }
  77. const onAddTable = (table: unknown) => {
  78. formData.value.tableList = [table]
  79. }
  80. </script>
  81. <template>
  82. <el-scrollbar class="w-full">
  83. <el-collapse expand-icon-position="left" :model-value="['1', '2', '3', '4', '5', '6', '7']">
  84. <el-collapse-item name="1">
  85. <template #title="{ isActive }">
  86. <div class="flex items-center justify-between">
  87. <span>数据表</span>
  88. <IconButton
  89. size="large"
  90. v-show="isActive"
  91. icon="iconoir:plus"
  92. link
  93. @click.stop="addDatabase"
  94. />
  95. </div>
  96. </template>
  97. <template v-for="table in formData.tableList" :key="table">
  98. <div
  99. class="px-12px flex items-center justify-between cursor-pointer mb-12px p-12px hover:bg-gray-100 border border-solid border-gray-300 rounded-8px"
  100. >
  101. <div class="left flex items-center gap-24px">
  102. <div class="icon w-40px h-40px bg-#ffb800 rounded-md grid place-items-center">
  103. <Icon icon="iconoir:database-solid" color="#fff" height="24" width="24" />
  104. </div>
  105. <div>
  106. <div class="text-#333 text-xs">{{ table.name }}</div>
  107. </div>
  108. </div>
  109. <IconButton icon="ep:delete" size="small" />
  110. </div>
  111. <div class="flex gap-4px">
  112. <el-tag
  113. v-for="column in table.columns"
  114. :key="column.name"
  115. type="info"
  116. effect="light"
  117. size="small"
  118. >{{ column.name }}</el-tag
  119. >
  120. </div>
  121. </template>
  122. <el-empty
  123. v-if="!formData.tableList.length"
  124. description="请添加一个数据表到此处"
  125. :image-size="40"
  126. />
  127. </el-collapse-item>
  128. <el-collapse-item name="2">
  129. <template #title="{ isActive }">
  130. <div class="flex items-center justify-between">
  131. <span>查询字段查询字段</span>
  132. <el-dropdown popper-class="w-200px" placement="bottom-end">
  133. <IconButton size="large" v-show="isActive" icon="iconoir:plus" link @click.stop />
  134. <template #dropdown>
  135. <el-dropdown-item
  136. v-for="column in columns"
  137. :key="column.name"
  138. @click="formData.fieldList.push(column)"
  139. >{{ column.name }}</el-dropdown-item
  140. >
  141. </template>
  142. </el-dropdown>
  143. </div>
  144. </template>
  145. <div v-for="field in formData.fieldList" :key="field.name" class="flex gap-4px mb-12px">
  146. <span>{{ field.name }}</span>
  147. <el-tag type="info" effect="light">{{ field.type }}</el-tag>
  148. </div>
  149. <el-empty v-if="!formData.fieldList.length" description="请添加查询字段" :image-size="40" />
  150. </el-collapse-item>
  151. <el-collapse-item title="查询条件" name="3"> </el-collapse-item>
  152. <el-collapse-item name="5">
  153. <template #title="{ isActive }">
  154. <div class="flex items-center justify-between">
  155. <span>排序方式</span>
  156. <el-dropdown popper-class="w-200px" placement="bottom-end">
  157. <IconButton size="large" v-show="isActive" icon="iconoir:plus" link @click.stop />
  158. <template #dropdown>
  159. <el-dropdown-item
  160. v-for="column in formData.fieldList"
  161. :key="column.name"
  162. @click="
  163. formData.sortList.push({
  164. name: column.name,
  165. type: column.type,
  166. sort: 'asc'
  167. })
  168. "
  169. >{{ column.name }}</el-dropdown-item
  170. >
  171. </template>
  172. </el-dropdown>
  173. </div>
  174. </template>
  175. <div
  176. v-for="field in formData.sortList"
  177. :key="field.name"
  178. class="flex items-center gap-4px mb-12px"
  179. >
  180. <div class="flex-1 flex justify-between">
  181. <span>{{ field.name }}</span>
  182. <el-tag type="info" effect="light">{{ field.type }}</el-tag>
  183. </div>
  184. <el-select style="width: 120px" v-model="field.sort" placeholder="请选择">
  185. <el-option label="升序" value="asc"></el-option>
  186. <el-option label="降序" value="desc"></el-option>
  187. </el-select>
  188. </div>
  189. <el-empty v-if="!formData.sortList.length" description="请添加排序字段" :image-size="40" />
  190. </el-collapse-item>
  191. <el-collapse-item title="查询上限" name="6">
  192. <el-input-number
  193. v-model="formData.limit"
  194. :min="1"
  195. :max="1000"
  196. style="width: 100%"
  197. controls-position="right"
  198. placeholder="请输入查询上限"
  199. />
  200. </el-collapse-item>
  201. <el-collapse-item title="输出" name="7">
  202. <el-collapse-item name="7-1">
  203. <template #title="{ isActive }">
  204. <div class="flex items-center justify-between">
  205. <span>outputList</span>
  206. <el-dropdown popper-class="w-200px" placement="bottom-end">
  207. <IconButton size="large" v-show="isActive" icon="iconoir:plus" link @click.stop />
  208. <template #dropdown>
  209. <el-dropdown-item
  210. v-for="column in formData.fieldList"
  211. :key="column.name"
  212. @click="
  213. formData.output.outputList.push({
  214. name: column.name,
  215. type: column.type
  216. })
  217. "
  218. >{{ column.name }}</el-dropdown-item
  219. >
  220. </template>
  221. </el-dropdown>
  222. </div>
  223. </template>
  224. <div
  225. v-for="field in formData.output.outputList"
  226. :key="field.name"
  227. class="flex items-center gap-4px mb-12px"
  228. >
  229. <span>{{ field.name }}</span>
  230. <el-tag type="info" effect="light">{{ field.type }}</el-tag>
  231. </div>
  232. </el-collapse-item>
  233. </el-collapse-item>
  234. </el-collapse>
  235. <div class="p-12px">
  236. <el-form-item label="异常处理" label-width="90px" label-position="left">
  237. <div class="w-full text-right">
  238. <el-select
  239. v-model="formData.exception"
  240. :options="exceptionOptions"
  241. style="width: 120px"
  242. />
  243. </div>
  244. </el-form-item>
  245. <div v-if="formData.exception === 'default_value'">
  246. <div class="text-12px text-gray-500">当发生异常时,指定默认数据输出</div>
  247. <el-form-item label="body" label-position="top">
  248. <el-input v-model="formData.exceptionDefaultValue.body" type="textarea" rows="3" />
  249. </el-form-item>
  250. <el-form-item label="status_code" label-position="top">
  251. <el-input-number
  252. controls-position="right"
  253. v-model="formData.exceptionDefaultValue.status_code"
  254. />
  255. </el-form-item>
  256. <el-form-item label="headers" label-position="top">
  257. <el-input v-model="formData.exceptionDefaultValue.headers" type="textarea" rows="5" />
  258. </el-form-item>
  259. </div>
  260. <div v-if="formData.exception === 'exception_branch'">
  261. <div class="text-12px text-gray-500">请在画布定义异常处理逻辑!</div>
  262. </div>
  263. </div>
  264. </el-scrollbar>
  265. <SelectTableModal ref="selectTableModalRef" @add="onAddTable" />
  266. </template>