basic.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <template>
  2. <a-card :bordered="false">
  3. <a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
  4. <a-row :gutter="16">
  5. <a-col :span="8">
  6. <a-form-item label="选择主表:" name="dbTable">
  7. <a-select
  8. v-model:value="formData.dbTable"
  9. :options="tableList"
  10. class="xn-wd"
  11. placeholder="请选择主表"
  12. @select="selectTableColumnsData(formData.dbTable, false)"
  13. show-search
  14. option-filter-prop="label"
  15. />
  16. </a-form-item>
  17. </a-col>
  18. <a-col :span="8">
  19. <a-form-item label="选择主键:" name="dbTableKey">
  20. <a-select
  21. v-model:value="formData.dbTableKey"
  22. :options="tableColumns"
  23. class="xn-wd"
  24. placeholder="选择主键"
  25. show-search
  26. option-filter-prop="label"
  27. />
  28. </a-form-item>
  29. </a-col>
  30. <a-col :span="8">
  31. <a-form-item label="表前缀移除:" name="tablePrefix">
  32. <a-radio-group
  33. v-model:value="formData.tablePrefix"
  34. :options="tablePrefixOptions"
  35. @change="tablePrefixChange"
  36. />
  37. </a-form-item>
  38. </a-col>
  39. <a-col :span="8">
  40. <a-form-item name="generateType">
  41. <template #label>
  42. <a-tooltip>
  43. <template #title>注:移动端代码生成目前只支持【压缩包】方式。</template>
  44. <question-circle-outlined />
  45. 生成方式:
  46. </a-tooltip>
  47. </template>
  48. <a-radio-group v-model:value="formData.generateType" :options="generateTypeOptions" />
  49. </a-form-item>
  50. </a-col>
  51. <a-col :span="8">
  52. <a-form-item label="所属模块:" name="module">
  53. <a-select
  54. v-model:value="formData.module"
  55. :options="moduleOptions"
  56. class="xn-wd"
  57. placeholder="请选择所属模块"
  58. @change="moduleChange(formData.module, false)"
  59. />
  60. </a-form-item>
  61. </a-col>
  62. <a-col :span="8">
  63. <a-form-item label="上级目录:" name="menuPid">
  64. <a-tree-select
  65. v-model:value="formData.menuPid"
  66. class="xn-wd"
  67. :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
  68. placeholder="请选择上级目录"
  69. allow-clear
  70. tree-default-expand-all
  71. :tree-data="menuTreeData"
  72. :field-names="{
  73. children: 'children',
  74. label: 'title',
  75. value: 'id'
  76. }"
  77. selectable="false"
  78. tree-line
  79. />
  80. </a-form-item>
  81. </a-col>
  82. <a-col :span="8">
  83. <a-form-item label="移动端所属模块:" name="mobileModule">
  84. <a-select
  85. v-model:value="formData.mobileModule"
  86. :options="mobileModuleList"
  87. class="xn-wd"
  88. placeholder="请选择移动端所属模块"
  89. allow-clear
  90. />
  91. </a-form-item>
  92. </a-col>
  93. <a-col :span="8">
  94. <a-form-item name="pluginName">
  95. <template #label>
  96. <a-tooltip>
  97. <template #title>
  98. 不想把代码生成到本框架指定插件名称下,可以新建一个plugin模块,并在这里改为新的名字。
  99. </template>
  100. <question-circle-outlined />
  101. </a-tooltip>
  102. &nbsp 插件名:
  103. </template>
  104. <a-input v-model:value="formData.pluginName" placeholder="请输入插件名" allow-clear />
  105. </a-form-item>
  106. </a-col>
  107. <a-col :span="8">
  108. <a-form-item label="包名:" name="packageName">
  109. <a-input v-model:value="formData.packageName" placeholder="请输入包名" allow-clear />
  110. </a-form-item>
  111. </a-col>
  112. <a-col :span="8">
  113. <a-form-item name="moduleName">
  114. <template #label>
  115. <a-tooltip>
  116. <template #title> 代码模块名就是包名后面的代码包,例如:vip.xiaonuo.*,*代表此模块名。 </template>
  117. <question-circle-outlined />
  118. </a-tooltip>
  119. &nbsp 模块名:
  120. </template>
  121. <a-input v-model:value="formData.moduleName" placeholder="请输入模块名" allow-clear />
  122. </a-form-item>
  123. </a-col>
  124. <a-col :span="8">
  125. <a-form-item label="功能名(菜单、注释):" name="functionName">
  126. <a-input v-model:value="formData.functionName" placeholder="请输入功能名" allow-clear />
  127. </a-form-item>
  128. </a-col>
  129. <a-col :span="8">
  130. <a-form-item name="busName">
  131. <template #label>
  132. <a-tooltip>
  133. <template #title> 业务名是代码生成后,存放controller、service等代码的文件夹名称。 </template>
  134. <question-circle-outlined />
  135. </a-tooltip>
  136. &nbsp 业务名:
  137. </template>
  138. <a-input v-model:value="formData.busName" placeholder="请输入业务名" allow-clear />
  139. </a-form-item>
  140. </a-col>
  141. <a-col :span="8">
  142. <a-form-item label="类名:" name="className">
  143. <a-input v-model:value="formData.className" placeholder="请输入类名" allow-clear />
  144. </a-form-item>
  145. </a-col>
  146. <a-col :span="8">
  147. <a-form-item label="作者:" name="authorName">
  148. <a-input v-model:value="formData.authorName" placeholder="请输入作者名" allow-clear />
  149. </a-form-item>
  150. </a-col>
  151. <a-col :span="8">
  152. <a-form-item name="formLayout">
  153. <template #label>
  154. <a-tooltip>
  155. <template #title> 垂直选项生成出来的前端表单代码为名称跟输入框是上下两行,反之水平则是一行。 </template>
  156. <question-circle-outlined />
  157. </a-tooltip>
  158. &nbsp 表单布局:
  159. </template>
  160. <a-radio-group v-model:value="formData.formLayout" :options="formLayoutOptions" />
  161. </a-form-item>
  162. </a-col>
  163. <a-col :span="8">
  164. <a-form-item name="gridWhether">
  165. <template #label>
  166. <a-tooltip>
  167. <template #title> 如果使用了栅格配置,即生成出来的前端代码,表单是一排两列,并非一排一列。 </template>
  168. <question-circle-outlined />
  169. </a-tooltip>
  170. &nbsp 使用栅格:
  171. </template>
  172. <a-radio-group v-model:value="formData.gridWhether" :options="gridWhetherOptions" />
  173. </a-form-item>
  174. </a-col>
  175. <a-col :span="8">
  176. <a-form-item label="排序:" name="sortCode">
  177. <a-input-number class="xn-wd" v-model:value="formData.sortCode" :max="100" />
  178. </a-form-item>
  179. </a-col>
  180. <a-col :span="8">
  181. <a-form-item label="表单模式:" name="formMode">
  182. <a-radio-group v-model:value="formData.formMode" :options="formModeOptions" />
  183. </a-form-item>
  184. </a-col>
  185. </a-row>
  186. </a-form>
  187. </a-card>
  188. </template>
  189. <script setup name="genBasic">
  190. import { required } from '@/utils/formRules'
  191. import tool from '@/utils/tool'
  192. import genBasicApi from '@/api/gen/genBasicApi'
  193. const formRef = ref()
  194. // 表单数据
  195. const formData = ref({})
  196. // 定义
  197. const mobileModuleList = ref([])
  198. const tableList = ref([])
  199. const tableColumns = ref([])
  200. const menuTreeData = ref([])
  201. const submitLoading = ref(false)
  202. const moduleOptions = ref()
  203. const generateTypeOptions = ref([
  204. {
  205. label: '压缩包',
  206. value: 'ZIP'
  207. },
  208. {
  209. label: '项目内',
  210. value: 'PRO'
  211. }
  212. ])
  213. const tablePrefixOptions = ref([
  214. {
  215. label: '移除',
  216. value: 'Y'
  217. },
  218. {
  219. label: '不移除',
  220. value: 'N'
  221. }
  222. ])
  223. const formLayoutOptions = ref([
  224. {
  225. label: '垂直',
  226. value: 'vertical'
  227. },
  228. {
  229. label: '水平',
  230. value: 'horizontal'
  231. }
  232. ])
  233. const gridWhetherOptions = ref([
  234. {
  235. label: '栅格布局',
  236. value: 'Y'
  237. },
  238. {
  239. label: '不使用',
  240. value: 'N'
  241. }
  242. ])
  243. const formModeOptions = ref([
  244. {
  245. label: '弹窗',
  246. value: 'dialog'
  247. },
  248. {
  249. label: '内嵌',
  250. value: 'inside'
  251. }
  252. ])
  253. // 打开抽屉
  254. const onOpen = (record) => {
  255. // 加载默认的模块
  256. moduleOptions.value = tool.data.get('MENU').map((item) => {
  257. return {
  258. label: item.name,
  259. value: item.id
  260. }
  261. })
  262. // 获取数据库中的所有表
  263. genBasicApi.basicTables().then((data) => {
  264. tableList.value = data.map((item) => {
  265. return {
  266. value: item['tableName'],
  267. label: `${item['tableRemark']}-${item['tableName']}`,
  268. tableRemark: item['tableRemark'] || item['tableName'],
  269. tableColumns: []
  270. }
  271. })
  272. if (record) {
  273. const params = {
  274. id: record.id
  275. }
  276. submitLoading.value = true
  277. genBasicApi
  278. .basicDetail(params)
  279. .then((data) => {
  280. formData.value = data
  281. // 让主键选中
  282. selectTableColumnsData(data.dbTable, true)
  283. // 让模块旁边的上级菜单选中
  284. moduleChange(data.module, true)
  285. })
  286. .finally(() => {
  287. submitLoading.value = false
  288. })
  289. } else {
  290. formData.value = {
  291. pluginName: 'snowy-plugin-biz',
  292. packageName: 'vip.xiaonuo',
  293. moduleName: 'biz',
  294. sortCode: 99,
  295. tablePrefix: 'N',
  296. generateType: 'PRO',
  297. formLayout: 'vertical',
  298. gridWhether: 'Y',
  299. formMode: 'inside',
  300. }
  301. }
  302. })
  303. // 获取移动端模块
  304. submitLoading.value = true
  305. genBasicApi
  306. .basicMobileModuleSelector()
  307. .then((data) => {
  308. mobileModuleList.value = data.map((item) => {
  309. return {
  310. value: item['id'],
  311. label: item['name']
  312. }
  313. })
  314. })
  315. .finally(() => {
  316. submitLoading.value = false
  317. })
  318. }
  319. // 默认要校验的
  320. const formRules = {
  321. pluginName: [required('请输入插件名')],
  322. moduleName: [required('请输入模块名')],
  323. tablePrefix: [required('请选择是否移除表前缀')],
  324. dbTable: [required('请选择主表')],
  325. dbTableKey: [required('请选择主表主键')],
  326. generateType: [required('请选择生成方式')],
  327. module: [required('请选择所属模块')],
  328. menuPid: [required('请选择上级目录')],
  329. functionName: [required('请输入功能名')],
  330. busName: [required('请输入业务名')],
  331. className: [required('请输入类名')],
  332. packageName: [required('请输入包名')],
  333. sortCode: [required('请选择排序')],
  334. formLayout: [required('请选择表单布局')],
  335. formMode: [required('请选择表单模式')],
  336. gridWhether: [required('请选择是否使用栅格')],
  337. authorName: [required('请输入作者名')]
  338. }
  339. // 选择模板的回调
  340. const moduleChange = (value, assign) => {
  341. if (!assign) {
  342. // 先去掉值
  343. formData.value.menuPid = undefined
  344. }
  345. // 加载默认的模块
  346. const menuTree = tool.data.get('MENU').find((item) => {
  347. if (item.id === value) {
  348. return item
  349. }
  350. })
  351. menuTreeData.value = [
  352. {
  353. id: '0',
  354. title: '顶级',
  355. menuType: 'CATALOG',
  356. children: traverseChildren(menuTree.children)
  357. }
  358. ]
  359. }
  360. // 遍历增加属性
  361. const traverseChildren = (data = []) => {
  362. // 递归遍历控件树
  363. const traverse = (array) => {
  364. array.forEach((element) => {
  365. if (element.menuType === 'CATALOG') {
  366. if (element.children) {
  367. traverse(element.children)
  368. }
  369. } else {
  370. // 设置不可用
  371. element.disabled = true
  372. element.selectable = false
  373. }
  374. })
  375. }
  376. traverse(data)
  377. return data
  378. }
  379. // 获取表字段
  380. const selectTableColumnsData = (tableName, assign) => {
  381. if (!assign) {
  382. formData.value.dbTableKey = undefined
  383. formFieldAssign(tableName)
  384. }
  385. // 通过这个 tableName 查到这个表下的字段
  386. const param = {
  387. tableName: tableName
  388. }
  389. genBasicApi.basicTableColumns(param).then((data) => {
  390. tableColumns.value = data.map((item) => {
  391. return {
  392. value: item['columnName'],
  393. label: item['columnRemark'] || item['columnName']
  394. }
  395. })
  396. })
  397. }
  398. // 点击选择是否移除前缀
  399. const tablePrefixChange = () => {
  400. const tableName = formData.value.dbTable
  401. if (tableName) {
  402. const tableNameHump = getTableNameToHump(tableName)
  403. formData.value.busName = tableNameHump.toLowerCase()
  404. }
  405. }
  406. // 表单内设置默认的值
  407. const formFieldAssign = (value) => {
  408. const data = tableList.value.find((item) => item.value === value)
  409. formData.value.functionName = data.tableRemark
  410. const tableNameHump = getTableNameToHump(data.value)
  411. formData.value.busName = tableNameHump.toLowerCase()
  412. formData.value.className = getClassName(data.value)
  413. }
  414. // 获取数据库表的驼峰命名
  415. const getTableNameToHump = (tableName) => {
  416. if (tableName) {
  417. const arr = tableName.toLowerCase().split('_')
  418. if (formData.value.tablePrefix === 'Y') {
  419. arr.splice(0, 1)
  420. }
  421. for (let i = 0; i < arr.length; i++) {
  422. // charAt()方法得到第一个字母,slice()得到第二个字母以后的字符串
  423. arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1)
  424. }
  425. return arr.join('')
  426. }
  427. return ''
  428. }
  429. // 获取数据库表的驼峰命名
  430. const getClassName = (tableName) => {
  431. if (tableName) {
  432. const arr = tableName.toLowerCase().split('_')
  433. for (let i = 0; i < arr.length; i++) {
  434. // charAt()方法得到第一个字母,slice()得到第二个字母以后的字符串
  435. arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1)
  436. }
  437. return arr.join('')
  438. }
  439. return ''
  440. }
  441. // 验证并提交数据
  442. const onSubmit = () => {
  443. return new Promise((resolve, reject) => {
  444. formRef.value
  445. .validate()
  446. .then(() => {
  447. submitLoading.value = true
  448. genBasicApi
  449. .submitForm(formData.value, formData.value.id)
  450. .then((data) => {
  451. resolve(data)
  452. })
  453. .finally(() => {
  454. submitLoading.value = false
  455. })
  456. })
  457. .catch((err) => {
  458. reject(err)
  459. })
  460. })
  461. }
  462. // 调用这个函数将子组件的一些数据和方法暴露出去
  463. defineExpose({
  464. onOpen,
  465. onSubmit
  466. })
  467. </script>
  468. <style scoped>
  469. .childAddButton {
  470. margin-bottom: 10px;
  471. }
  472. .form-row {
  473. background-color: var(--item-hover-bg);
  474. margin-left: 0px !important;
  475. }
  476. .form-row-con {
  477. padding-bottom: 5px;
  478. padding-top: 5px;
  479. padding-left: 15px;
  480. }
  481. .form-div {
  482. padding-top: 10px;
  483. }
  484. </style>