index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  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. tableColumnList:[],//数据表字段集合
  254. formData: {}, //表单数据
  255. locale: zhCN,
  256. customComponents,
  257. activeKey: 1,
  258. updateTime: 0,
  259. updateRecordTime: 0,
  260. startType: "",
  261. revoke: null,
  262. recordList: [],
  263. redoList: [],
  264. noModel: [
  265. "button",
  266. "divider",
  267. "card",
  268. "grid",
  269. "tabs",
  270. "table",
  271. "alert",
  272. "text",
  273. "html"
  274. ],
  275. data: {
  276. list: [],
  277. config: {
  278. layout: "horizontal",
  279. labelCol: { xs: 4, sm: 4, md: 4, lg: 4, xl: 4, xxl: 4 },
  280. labelWidth: 100,
  281. labelLayout: "flex",
  282. wrapperCol: { xs: 18, sm: 18, md: 18, lg: 18, xl: 18, xxl: 18 },
  283. hideRequiredMark: false,
  284. customStyle: ""
  285. }
  286. },
  287. previewOptions: {
  288. width: 850
  289. },
  290. selectItem: {
  291. key: ""
  292. }
  293. };
  294. },
  295. components: {
  296. kHeader,
  297. // kFooter,
  298. operatingArea,
  299. collapseItem,
  300. kJsonModal,
  301. kCodeModal,
  302. importJsonModal,
  303. previewModal,
  304. kFormComponentPanel,
  305. formItemProperties,
  306. formProperties,
  307. queryModal,
  308. selectTbTableInfoModal
  309. },
  310. watch: {
  311. data: {
  312. handler(e) {
  313. this.$nextTick(() => {
  314. this.revoke.push(e);
  315. });
  316. },
  317. deep: true,
  318. immediate: true
  319. }
  320. },
  321. computed: {
  322. basicsArray() {
  323. // 计算需要显示的基础字段
  324. return basicsList.filter(item => this.fields.includes(item.type));
  325. },
  326. layoutArray() {
  327. // 计算需要显示的布局字段
  328. return layoutList.filter(item => this.fields.includes(item.type));
  329. },
  330. collapseDefaultActiveKey() {
  331. // 计算当前展开的控件列表
  332. const defaultActiveKey = window.localStorage.getItem(
  333. "collapseDefaultActiveKey"
  334. );
  335. if (defaultActiveKey) {
  336. return defaultActiveKey.split(",");
  337. } else {
  338. return ["1"];
  339. }
  340. }
  341. },
  342. methods: {
  343. generateKey(list, index) {
  344. // 生成key值
  345. const key = list[index].type + "_" + new Date().getTime();
  346. this.$set(list, index, {
  347. ...list[index],
  348. key,
  349. model: key
  350. });
  351. if (this.noModel.includes(list[index].type)) {
  352. // 删除不需要的model属性
  353. delete list[index].model;
  354. }
  355. },
  356. handleListPush(item) {
  357. if(this.formData.businessTable){
  358. // 双击控件按钮push到list
  359. // 生成key值
  360. if (!this.selectItem.key) {
  361. // 在没有选择表单时,将数据push到this.data.list
  362. const key = item.type + "_" + new Date().getTime();
  363. item = {
  364. ...item,
  365. key,
  366. model: key,
  367. };
  368. if (this.noModel.includes(item.type)) {
  369. // 删除不需要的model属性
  370. delete item.model;
  371. }
  372. const itemString = JSON.stringify(item);
  373. const record = JSON.parse(itemString);
  374. // 删除icon及compoent属性
  375. delete record.icon;
  376. delete record.component;
  377. this.data.list.push(record);
  378. this.handleSetSelectItem(record);
  379. return false;
  380. }
  381. this.$refs.KFCP.handleCopy(false, item);
  382. }else{
  383. this.$message.error("请先选择表单属性中的关联数据表")
  384. }
  385. },
  386. handleOpenJsonModal() {
  387. // 打开json预览模态框
  388. this.$refs.jsonModal.jsonData = this.data;
  389. this.$refs.jsonModal.formData = this.formData;
  390. this.$refs.jsonModal.visible = true;
  391. },
  392. handleOpenCodeModal() {
  393. // 打开代码预览模态框
  394. this.$refs.codeModal.jsonData = this.data;
  395. this.$refs.codeModal.visible = true;
  396. },
  397. handleOpenImportJsonModal() {
  398. // 打开json预览模态框
  399. this.$refs.importJsonModal.jsonData = this.data;
  400. this.$refs.importJsonModal.handleSetSelectItem = this.handleSetSelectItem;
  401. this.$refs.importJsonModal.visible = true;
  402. },
  403. handlePreview() {
  404. // 打开预览模态框
  405. this.$refs.previewModal.jsonData = this.data;
  406. this.$refs.previewModal.previewWidth = this.previewOptions.width;
  407. this.$refs.previewModal.visible = true;
  408. },
  409. handleQuery() {
  410. // 打开查询模态框
  411. this.$refs.queryModal.jsonData = this.data;
  412. this.$refs.queryModal.formData = this.formData;
  413. // this.$refs.queryModal.previewWidth = this.previewOptions.width;
  414. this.$refs.queryModal.visible = true;
  415. },
  416. handleReset() {
  417. // 清空
  418. if (this.hideResetHint) {
  419. this.formData = {};
  420. this.$refs.queryModal.formData = {};
  421. this.tableColumnList=[];
  422. // 不显示提示直接清空
  423. this.resetData();
  424. return;
  425. }
  426. this.$confirm({
  427. title: "警告",
  428. content: "是否确认清空内容?",
  429. okText: "是",
  430. okType: "danger",
  431. cancelText: "否",
  432. onOk: () => {
  433. this.resetData();
  434. }
  435. });
  436. },
  437. resetData() {
  438. this.data = {
  439. list: [],
  440. config: {
  441. layout: "horizontal",
  442. labelCol: { xs: 4, sm: 4, md: 4, lg: 4, xl: 4, xxl: 4 },
  443. labelWidth: 100,
  444. labelLayout: "flex",
  445. wrapperCol: { xs: 18, sm: 18, md: 18, lg: 18, xl: 18, xxl: 18 },
  446. hideRequiredMark: false,
  447. customStyle: ""
  448. }
  449. };
  450. this.handleSetSelectItem({ key: "" });
  451. this.$message.success("已清空");
  452. },
  453. handleSetSelectItem(record) {
  454. // 操作间隔不能低于100毫秒
  455. const newTime = new Date().getTime();
  456. if (newTime - this.updateTime < 100) {
  457. return false;
  458. }
  459. this.updateTime = newTime;
  460. // 设置selectItem的值
  461. this.selectItem = record;
  462. ///获取表字段的下拉数据
  463. //判断字段下拉数据是否有集合
  464. if(!this.tableColumnList||this.tableColumnList.length<=0){//没有则查询
  465. //获取表字段下拉数据接口
  466. getTableColumnList(this.formData.businessTable).then(res=>{
  467. this.tableColumnList=res.data.result;//表字段下拉数据
  468. });
  469. }
  470. // 判断是否选中控件,如果选中则弹出属性面板,否则关闭属性面板
  471. if (record.key) {
  472. this.startType = record.type;
  473. this.changeTab(2);
  474. } else {
  475. this.changeTab(1);
  476. }
  477. },
  478. /**
  479. * @description: 切换属性设置面板
  480. * @param {*}
  481. * @return {*}
  482. */
  483. changeTab(e) {
  484. this.activeKey = e;
  485. },
  486. /**
  487. * @Author: kcz
  488. * @description: 遍历json结构,获取所有字段
  489. * @param {*}
  490. * @return {*} Array
  491. */
  492. getFieldSchema() {
  493. const fields = [];
  494. const traverse = array => {
  495. array.forEach(element => {
  496. if (element.type === "grid" || element.type === "tabs") {
  497. // 栅格布局
  498. element.columns.forEach(item => {
  499. traverse(item.list);
  500. });
  501. } else if (element.type === "card") {
  502. // 卡片布局
  503. traverse(element.list);
  504. } else if (element.type === "batch") {
  505. // 动态表格内复制
  506. traverse(element.list);
  507. } else if (element.type === "table") {
  508. // 表格布局
  509. element.trs.forEach(item => {
  510. item.tds.forEach(val => {
  511. traverse(val.list);
  512. });
  513. });
  514. } else {
  515. if (element.model) {
  516. fields.push(element);
  517. }
  518. }
  519. });
  520. };
  521. traverse(this.data.list);
  522. return fields;
  523. },
  524. handleSetData(data) {
  525. // 用于父组件赋值
  526. try {
  527. if (typeof data !== "object") {
  528. return false;
  529. } else {
  530. this.data = data;
  531. // 导入json数据后,需要清除已选择key
  532. this.handleSetSelectItem({ key: "" });
  533. }
  534. return true;
  535. } catch (error) {
  536. console.error(error);
  537. return false;
  538. }
  539. },
  540. collapseChange(val) {
  541. // 点击collapse时,保存当前collapse状态
  542. window.localStorage.setItem("collapseDefaultActiveKey", val);
  543. },
  544. handleStart(type) {
  545. this.startType = type;
  546. },
  547. /**
  548. * @description: 撤销
  549. * @param {*}
  550. * @return {*}
  551. */
  552. handleUndo() {
  553. const record = this.revoke.undo();
  554. if (!record) {
  555. return false;
  556. }
  557. this.data = record;
  558. this.handleSetSelectItem({ key: "" });
  559. },
  560. /**
  561. * @description: 重做
  562. * @param {*}
  563. * @return {*}
  564. */
  565. handleRedo() {
  566. const record = this.revoke.redo();
  567. if (!record) {
  568. return false;
  569. }
  570. this.data = record;
  571. },
  572. handleSave() {
  573. // 保存函数
  574. this.$emit("save", JSON.stringify(this.data));
  575. },
  576. getValue() {
  577. // 获取数据
  578. return this.data;
  579. },
  580. handleClose() {
  581. this.$emit("close");
  582. }
  583. },
  584. created() {
  585. this.revoke = new Revoke();
  586. this.recordList = this.revoke.recordList;
  587. this.redoList = this.revoke.redoList;
  588. console.log(this.$route.query.tableName);
  589. //判断是否有接收到表明
  590. if (this.$route.query.tableName) {
  591. //有则根据表明查询表单json以及相关数据
  592. getFormByBusinessTable(this.$route.query.tableName).then(res => {
  593. if (res.data.success) {
  594. if(res.data.result.tbTableInfoList!=null&&res.data.result.tbTableInfoList.length>1){
  595. // 打开查询模态框
  596. // this.$refs.queryModal.jsonData = this.data;
  597. // this.$refs.queryModal.formData = this.formData;
  598. // this.$refs.queryModal.previewWidth = this.previewOptions.width;
  599. this.$refs.selectTbTableInfoModal.visible = true;
  600. this.$refs.selectTbTableInfoModal.dataSource=res.data.result.tbTableInfoList;
  601. this.$refs.selectTbTableInfoModal.jsonData = this.data;//表单json
  602. this.$refs.selectTbTableInfoModal.formData = this.formData;//表单相关字段数据
  603. }else{
  604. //获取Json字符串装json格式
  605. const editorJsonData = res.data.result.jsonContent;
  606. const jsonData = {};
  607. //获取json展示的数据
  608. jsonData.list = editorJsonData.list;
  609. jsonData.config = editorJsonData.config;
  610. jsonData.config.layout = editorJsonData.config.layout;
  611. this.data = jsonData;
  612. //当前填写数据存储,用于其他页面获取
  613. this.formData.businessTable = this.$route.query.tableName; //数据库表明
  614. this.formData.text = res.data.result.text; //表单标题
  615. // this.$message.success("查询成功");
  616. }
  617. } else {
  618. this.$message.error(res.data.message);
  619. }
  620. });
  621. }
  622. }
  623. };
  624. //根据表名称获取表字段与表说明
  625. // function getTableColumnListShow(item,formData){
  626. // getTableColumnList(formData.businessTable).then(res=>{
  627. // if(res.data.success){
  628. // item.tableList=res.data.result;
  629. // }
  630. // });
  631. // item.tableList=[
  632. // {columnName:"123",columnComment:"123"}
  633. // ]
  634. // }
  635. </script>