index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. <template>
  2. <a-config-provider :locale="locale">
  3. <div class="form-designer-container-9136076486841527">
  4. <k-header v-if="showHead" :title="title" />
  5. <!-- 操作区域 start -->
  6. <operatingArea
  7. v-if="toolbarsTop"
  8. :showToolbarsText="showToolbarsText"
  9. :toolbars="toolbars"
  10. @handleSave="handleSave"
  11. @handlePreview="handlePreview"
  12. @handleOpenImportJsonModal="handleOpenImportJsonModal"
  13. @handleOpenCodeModal="handleOpenCodeModal"
  14. @handleOpenJsonModal="handleOpenJsonModal"
  15. @handleReset="handleReset"
  16. @handleClose="handleClose"
  17. @handleUndo="handleUndo"
  18. @handleRedo="handleRedo"
  19. :recordList="recordList"
  20. :redoList="redoList"
  21. >
  22. <template slot="left-action">
  23. <slot name="left-action"></slot>
  24. </template>
  25. <template slot="right-action">
  26. <slot name="right-action"></slot>
  27. </template>
  28. </operatingArea>
  29. <!-- 操作区域 end -->
  30. <div
  31. class="content"
  32. :class="{
  33. 'show-head': showHead,
  34. 'toolbars-top': toolbarsTop,
  35. 'show-head-and-toolbars-top': toolbarsTop && showHead
  36. }"
  37. >
  38. <!-- 左侧控件区域 start -->
  39. <aside class="left">
  40. <a-collapse @change="collapseChange" :defaultActiveKey="collapseDefaultActiveKey">
  41. <!-- 基础控件 start -->
  42. <a-collapse-panel v-if="basicsArray.length > 0" header="基础控件" key="1">
  43. <collapseItem
  44. :list="basicsArray"
  45. @generateKey="generateKey"
  46. @handleListPush="handleListPush"
  47. @start="handleStart"
  48. />
  49. </a-collapse-panel>
  50. <!-- 基础控件 end -->
  51. <!-- 自定义控件 start -->
  52. <a-collapse-panel
  53. v-if="customComponents.list.length > 0"
  54. :header="customComponents.title"
  55. key="3"
  56. >
  57. <collapseItem
  58. :list="customComponents.list"
  59. @generateKey="generateKey"
  60. @handleListPush="handleListPush"
  61. @start="handleStart"
  62. />
  63. </a-collapse-panel>
  64. <!-- 自定义控件 end -->
  65. <!-- 布局控件 start -->
  66. <a-collapse-panel v-if="layoutArray.length > 0" header="布局控件" key="4">
  67. <collapseItem
  68. :list="layoutArray"
  69. @generateKey="generateKey"
  70. @handleListPush="handleListPush"
  71. @start="handleStart"
  72. />
  73. </a-collapse-panel>
  74. <!-- 布局控件 end -->
  75. </a-collapse>
  76. </aside>
  77. <!-- 左侧控件区域 end -->
  78. <!-- 中间面板区域 start -->
  79. <section>
  80. <!-- 操作区域 start -->
  81. <operatingArea
  82. v-if="!toolbarsTop"
  83. :showToolbarsText="showToolbarsText"
  84. :toolbars="toolbars"
  85. @handleSave="handleSave"
  86. @handlePreview="handlePreview"
  87. @handleOpenImportJsonModal="handleOpenImportJsonModal"
  88. @handleOpenCodeModal="handleOpenCodeModal"
  89. @handleOpenJsonModal="handleOpenJsonModal"
  90. @handleReset="handleReset"
  91. @handleClose="handleClose"
  92. @handleUndo="handleUndo"
  93. @handleRedo="handleRedo"
  94. @handleQuery="handleQuery"
  95. :recordList="recordList"
  96. :redoList="redoList"
  97. >
  98. <template slot="left-action">
  99. <slot name="left-action"></slot>
  100. </template>
  101. <template slot="right-action">
  102. <slot name="right-action"></slot>
  103. </template>
  104. </operatingArea>
  105. <!-- 操作区域 end -->
  106. <k-form-component-panel
  107. :class="{ 'no-toolbars-top': !toolbarsTop }"
  108. :data="data"
  109. :selectItem="selectItem"
  110. :noModel="noModel"
  111. :hideModel="hideModel"
  112. :startType="startType"
  113. ref="KFCP"
  114. @handleSetSelectItem="handleSetSelectItem"
  115. />
  116. <!-- 操作区域 start -->
  117. <k-json-modal ref="jsonModal" />
  118. <k-code-modal ref="codeModal" />
  119. <importJsonModal ref="importJsonModal" />
  120. <previewModal ref="previewModal" />
  121. <!-- 查询弹框 -->
  122. <queryModal ref="queryModal" />
  123. <!-- 同表多个表单先择弹框 -->
  124. <selectTbTableInfoModal ref="selectTbTableInfoModal"/>
  125. </section>
  126. <!-- 中间面板区域 end -->
  127. <!-- 右侧控件属性区域 start -->
  128. <aside class="right">
  129. <a-tabs :activeKey="activeKey" @change="changeTab" :tabBarStyle="{ margin: 0 }">
  130. <a-tab-pane :key="1" tab="表单属性设置">
  131. <formProperties :config="data.config" :formData="formData" :previewOptions="previewOptions" />
  132. </a-tab-pane>
  133. <a-tab-pane :key="2" tab="控件属性设置">
  134. <formItemProperties
  135. class="form-item-properties"
  136. :selectItem="selectItem"
  137. :hideModel="hideModel"
  138. :tableColumnList="tableColumnList"
  139. />
  140. </a-tab-pane>
  141. </a-tabs>
  142. </aside>
  143. <!-- 右侧控件属性区域 end -->
  144. </div>
  145. <!-- <k-footer /> -->
  146. </div>
  147. </a-config-provider>
  148. </template>
  149. <script>
  150. /*
  151. * author kcz
  152. * date 2019-11-20
  153. * description 表单设计器
  154. */
  155. import kHeader from "./module/header";
  156. import operatingArea from "./module/operatingArea";
  157. // import kFooter from "./module/footer";
  158. import kFormComponentPanel from "./module/formComponentPanel";
  159. import kJsonModal from "./module/jsonModal";
  160. import kCodeModal from "./module/codeModal";
  161. import collapseItem from "./module/collapseItem";
  162. import importJsonModal from "./module/importJsonModal";
  163. import queryModal from "./module/queryModal";
  164. import selectTbTableInfoModal from "./module/selectTbTableInfoModal";
  165. import previewModal from "../KFormPreview/index.vue";
  166. import zhCN from "ant-design-vue/lib/locale-provider/zh_CN";
  167. import { Revoke } from "../core/revoke";
  168. import {
  169. basicsList,
  170. layoutList,
  171. customComponents
  172. } from "./config/formItemsConfig";
  173. import formItemProperties from "./module/formItemProperties";
  174. import formProperties from "./module/formProperties";
  175. import { getFormByBusinessTable, getTableColumnList } from "../api/api";
  176. export default {
  177. name: "KFormDesign",
  178. props: {
  179. title: {
  180. type: String,
  181. default: "表单设计器"
  182. },
  183. showHead: {
  184. type: Boolean,
  185. default: true
  186. },
  187. hideResetHint: {
  188. type: Boolean,
  189. default: false
  190. },
  191. toolbarsTop: {
  192. type: Boolean,
  193. default: false
  194. },
  195. toolbars: {
  196. type: Array,
  197. default: () => [
  198. "save",
  199. "preview",
  200. "importJson",
  201. "exportJson",
  202. "exportCode",
  203. "reset",
  204. "close",
  205. "undo",
  206. "redo"
  207. ]
  208. },
  209. showToolbarsText: {
  210. type: Boolean,
  211. default: false
  212. },
  213. fields: {
  214. type: Array,
  215. default: () => [
  216. "input",
  217. "textarea",
  218. "number",
  219. "select",
  220. "checkbox",
  221. "radio",
  222. "date",
  223. "time",
  224. "rate",
  225. "slider",
  226. "uploadFile",
  227. "uploadImg",
  228. "cascader",
  229. "treeSelect",
  230. "batch",
  231. "selectInputList",
  232. "editor",
  233. "switch",
  234. "button",
  235. "alert",
  236. "text",
  237. "html",
  238. "divider",
  239. "card",
  240. "tabs",
  241. "grid",
  242. "table"
  243. ]
  244. },
  245. hideModel: {
  246. // 隐藏数据字段
  247. type: Boolean,
  248. default: false
  249. }
  250. },
  251. data() {
  252. return {
  253. businessTableHC:"",//用来记录关联的数据库表
  254. tableColumnList:[],//数据表字段集合
  255. formData: {}, //表单数据
  256. locale: zhCN,
  257. customComponents,
  258. activeKey: 1,
  259. updateTime: 0,
  260. updateRecordTime: 0,
  261. startType: "",
  262. revoke: null,
  263. recordList: [],
  264. redoList: [],
  265. noModel: [
  266. "button",
  267. "divider",
  268. "card",
  269. "grid",
  270. "tabs",
  271. "table",
  272. "alert",
  273. "text",
  274. "html"
  275. ],
  276. data: {
  277. list: [],
  278. config: {
  279. layout: "horizontal",
  280. labelCol: { xs: 4, sm: 4, md: 4, lg: 4, xl: 4, xxl: 4 },
  281. labelWidth: 100,
  282. labelLayout: "flex",
  283. wrapperCol: { xs: 18, sm: 18, md: 18, lg: 18, xl: 18, xxl: 18 },
  284. hideRequiredMark: false,
  285. customStyle: ""
  286. }
  287. },
  288. previewOptions: {
  289. width: 850
  290. },
  291. selectItem: {
  292. key: ""
  293. }
  294. };
  295. },
  296. components: {
  297. kHeader,
  298. // kFooter,
  299. operatingArea,
  300. collapseItem,
  301. kJsonModal,
  302. kCodeModal,
  303. importJsonModal,
  304. previewModal,
  305. kFormComponentPanel,
  306. formItemProperties,
  307. formProperties,
  308. queryModal,
  309. selectTbTableInfoModal
  310. },
  311. watch: {
  312. data: {
  313. handler(e) {
  314. this.$nextTick(() => {
  315. this.revoke.push(e);
  316. });
  317. },
  318. deep: true,
  319. immediate: true
  320. }
  321. },
  322. computed: {
  323. basicsArray() {
  324. // 计算需要显示的基础字段
  325. return basicsList.filter(item => this.fields.includes(item.type));
  326. },
  327. layoutArray() {
  328. // 计算需要显示的布局字段
  329. return layoutList.filter(item => this.fields.includes(item.type));
  330. },
  331. collapseDefaultActiveKey() {
  332. // 计算当前展开的控件列表
  333. const defaultActiveKey = window.localStorage.getItem(
  334. "collapseDefaultActiveKey"
  335. );
  336. if (defaultActiveKey) {
  337. return defaultActiveKey.split(",");
  338. } else {
  339. return ["1"];
  340. }
  341. }
  342. },
  343. methods: {
  344. generateKey(list, index) {
  345. // 生成key值
  346. const key = list[index].type + "_" + new Date().getTime();
  347. this.$set(list, index, {
  348. ...list[index],
  349. key,
  350. model: key
  351. });
  352. if (this.noModel.includes(list[index].type)) {
  353. // 删除不需要的model属性
  354. delete list[index].model;
  355. }
  356. },
  357. handleListPush(item) {
  358. if(this.formData.businessTable){
  359. // 双击控件按钮push到list
  360. // 生成key值
  361. if (!this.selectItem.key) {
  362. // 在没有选择表单时,将数据push到this.data.list
  363. const key = item.type + "_" + new Date().getTime();
  364. item = {
  365. ...item,
  366. key,
  367. model: key,
  368. };
  369. if (this.noModel.includes(item.type)) {
  370. // 删除不需要的model属性
  371. delete item.model;
  372. }
  373. const itemString = JSON.stringify(item);
  374. const record = JSON.parse(itemString);
  375. // 删除icon及compoent属性
  376. delete record.icon;
  377. delete record.component;
  378. this.data.list.push(record);
  379. this.handleSetSelectItem(record);
  380. return false;
  381. }
  382. this.$refs.KFCP.handleCopy(false, item);
  383. }else{
  384. this.$message.error("请先选择表单属性中的关联数据表")
  385. }
  386. },
  387. handleOpenJsonModal() {
  388. // 打开json预览模态框
  389. this.$refs.jsonModal.jsonData = this.data;
  390. this.$refs.jsonModal.formData =JSON.parse(JSON.stringify(this.formData));
  391. this.$refs.jsonModal.visible = true;
  392. },
  393. handleOpenCodeModal() {
  394. // 打开代码预览模态框
  395. this.$refs.codeModal.jsonData = this.data;
  396. this.$refs.codeModal.visible = true;
  397. },
  398. handleOpenImportJsonModal() {
  399. // 打开json预览模态框
  400. this.$refs.importJsonModal.jsonData = this.data;
  401. this.$refs.importJsonModal.handleSetSelectItem = this.handleSetSelectItem;
  402. this.$refs.importJsonModal.visible = true;
  403. },
  404. handlePreview() {
  405. // 打开预览模态框
  406. this.$refs.previewModal.jsonData = this.data;
  407. this.$refs.previewModal.previewWidth = this.previewOptions.width;
  408. this.$refs.previewModal.visible = true;
  409. },
  410. handleQuery() {
  411. // 打开查询模态框
  412. this.$refs.queryModal.jsonData = this.data;
  413. this.$refs.queryModal.formData = this.formData;
  414. // this.$refs.queryModal.previewWidth = this.previewOptions.width;
  415. this.$refs.queryModal.visible = true;
  416. },
  417. handleReset() {
  418. // 清空
  419. if (this.hideResetHint) {
  420. this.formData = {};
  421. this.$refs.queryModal.formData = {};
  422. this.tableColumnList=[];
  423. // 不显示提示直接清空
  424. this.resetData();
  425. return;
  426. }
  427. this.$confirm({
  428. title: "警告",
  429. content: "是否确认清空内容?",
  430. okText: "是",
  431. okType: "danger",
  432. cancelText: "否",
  433. onOk: () => {
  434. this.resetData();
  435. }
  436. });
  437. },
  438. resetData() {
  439. this.data = {
  440. list: [],
  441. config: {
  442. layout: "horizontal",
  443. labelCol: { xs: 4, sm: 4, md: 4, lg: 4, xl: 4, xxl: 4 },
  444. labelWidth: 100,
  445. labelLayout: "flex",
  446. wrapperCol: { xs: 18, sm: 18, md: 18, lg: 18, xl: 18, xxl: 18 },
  447. hideRequiredMark: false,
  448. customStyle: ""
  449. }
  450. };
  451. this.handleSetSelectItem({ key: "" });
  452. this.$message.success("已清空");
  453. },
  454. handleSetSelectItem(record) {
  455. // 操作间隔不能低于100毫秒
  456. const newTime = new Date().getTime();
  457. if (newTime - this.updateTime < 100) {
  458. return false;
  459. }
  460. this.updateTime = newTime;
  461. // 设置selectItem的值
  462. this.selectItem = record;
  463. ///获取表字段的下拉数据
  464. //判断字段下拉数据是否有集合 或者关联的数据库表有改动
  465. if(!this.tableColumnList||this.tableColumnList.length<=0||(this.formData.businessTable!=this.businessTableHC)){//没有则查询
  466. //获取表字段下拉数据接口
  467. getTableColumnList(this.formData.businessTable).then(res=>{
  468. this.businessTableHC=this.formData.businessTable;
  469. this.tableColumnList=res.data.result;//表字段下拉数据
  470. });
  471. }
  472. // 判断是否选中控件,如果选中则弹出属性面板,否则关闭属性面板
  473. if (record.key) {
  474. this.startType = record.type;
  475. this.changeTab(2);
  476. } else {
  477. this.changeTab(1);
  478. }
  479. },
  480. /**
  481. * @description: 切换属性设置面板
  482. * @param {*}
  483. * @return {*}
  484. */
  485. changeTab(e) {
  486. this.activeKey = e;
  487. },
  488. /**
  489. * @Author: kcz
  490. * @description: 遍历json结构,获取所有字段
  491. * @param {*}
  492. * @return {*} Array
  493. */
  494. getFieldSchema() {
  495. const fields = [];
  496. const traverse = array => {
  497. array.forEach(element => {
  498. if (element.type === "grid" || element.type === "tabs") {
  499. // 栅格布局
  500. element.columns.forEach(item => {
  501. traverse(item.list);
  502. });
  503. } else if (element.type === "card") {
  504. // 卡片布局
  505. traverse(element.list);
  506. } else if (element.type === "batch") {
  507. // 动态表格内复制
  508. traverse(element.list);
  509. } else if (element.type === "table") {
  510. // 表格布局
  511. element.trs.forEach(item => {
  512. item.tds.forEach(val => {
  513. traverse(val.list);
  514. });
  515. });
  516. } else {
  517. if (element.model) {
  518. fields.push(element);
  519. }
  520. }
  521. });
  522. };
  523. traverse(this.data.list);
  524. return fields;
  525. },
  526. handleSetData(data) {
  527. // 用于父组件赋值
  528. try {
  529. if (typeof data !== "object") {
  530. return false;
  531. } else {
  532. this.data = data;
  533. // 导入json数据后,需要清除已选择key
  534. this.handleSetSelectItem({ key: "" });
  535. }
  536. return true;
  537. } catch (error) {
  538. console.error(error);
  539. return false;
  540. }
  541. },
  542. collapseChange(val) {
  543. // 点击collapse时,保存当前collapse状态
  544. window.localStorage.setItem("collapseDefaultActiveKey", val);
  545. },
  546. handleStart(type) {
  547. this.startType = type;
  548. },
  549. /**
  550. * @description: 撤销
  551. * @param {*}
  552. * @return {*}
  553. */
  554. handleUndo() {
  555. const record = this.revoke.undo();
  556. if (!record) {
  557. return false;
  558. }
  559. this.data = record;
  560. this.handleSetSelectItem({ key: "" });
  561. },
  562. /**
  563. * @description: 重做
  564. * @param {*}
  565. * @return {*}
  566. */
  567. handleRedo() {
  568. const record = this.revoke.redo();
  569. if (!record) {
  570. return false;
  571. }
  572. this.data = record;
  573. },
  574. handleSave() {
  575. // 保存函数
  576. this.$emit("save", JSON.stringify(this.data));
  577. },
  578. getValue() {
  579. // 获取数据
  580. return this.data;
  581. },
  582. handleClose() {
  583. this.$emit("close");
  584. }
  585. },
  586. created() {
  587. this.revoke = new Revoke();
  588. this.recordList = this.revoke.recordList;
  589. this.redoList = this.revoke.redoList;
  590. console.log(this.$route.query.tableName);
  591. //判断是否有接收到表明
  592. if (this.$route.query.tableName) {
  593. //有则根据表明查询表单json以及相关数据
  594. getFormByBusinessTable(this.$route.query.tableName).then(res => {
  595. if (res.data.success) {
  596. if(res.data.result.tbTableInfoList!=null&&res.data.result.tbTableInfoList.length>1){
  597. // 打开查询模态框
  598. // this.$refs.queryModal.jsonData = this.data;
  599. // this.$refs.queryModal.formData = this.formData;
  600. // this.$refs.queryModal.previewWidth = this.previewOptions.width;
  601. this.$refs.selectTbTableInfoModal.visible = true;
  602. this.$refs.selectTbTableInfoModal.dataSource=res.data.result.tbTableInfoList;
  603. this.$refs.selectTbTableInfoModal.jsonData = this.data;//表单json
  604. this.$refs.selectTbTableInfoModal.formData = this.formData;//表单相关字段数据
  605. }else{
  606. //获取Json字符串装json格式
  607. const editorJsonData = res.data.result.jsonContent;
  608. const jsonData = {};
  609. //获取json展示的数据
  610. jsonData.list = editorJsonData.list;
  611. jsonData.config = editorJsonData.config;
  612. jsonData.config.layout = editorJsonData.config.layout;
  613. this.data = jsonData;
  614. //当前填写数据存储,用于其他页面获取
  615. this.formData.businessTable = this.$route.query.tableName; //数据库表明
  616. this.formData.text = res.data.result.text; //表单标题
  617. this.formData.stepMemo=res.data.result.stepMemo;//表单备注
  618. this.formData.type=res.data.result.type;//表单类型
  619. // this.$message.success("查询成功");
  620. }
  621. } else {
  622. this.$message.error(res.data.message);
  623. }
  624. });
  625. }
  626. }
  627. };
  628. //根据表名称获取表字段与表说明
  629. // function getTableColumnListShow(item,formData){
  630. // getTableColumnList(formData.businessTable).then(res=>{
  631. // if(res.data.success){
  632. // item.tableList=res.data.result;
  633. // }
  634. // });
  635. // item.tableList=[
  636. // {columnName:"123",columnComment:"123"}
  637. // ]
  638. // }
  639. </script>