ss.html 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. <html lang="zh">
  2. <head>
  3. <meta charset="UTF-8">
  4. <!-- Import style -->
  5. <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"/>
  6. <!-- Import Vue 2.7 -->
  7. <script src="https://unpkg.com/vue@2"></script>
  8. <!-- Import element-ui -->
  9. <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  10. <!-- Import formCreate -->
  11. <script src="https://unpkg.com/@form-create/element-ui@super"></script>
  12. </head>
  13. <body>
  14. <div id="app">
  15. <form-create :rule="rule" :option="options" v-model:value="formData" v-model="api" @submit="onSubmit"></form-create>
  16. </div>
  17. <script>
  18. // ====== 自定义代码开始 ======
  19. var zkqyTable = {
  20. name: 'zkqyTable',
  21. props: ['pageId'], // 声明接收的 props
  22. template: `
  23. <div class="zkqy-table">
  24. <div class="table-container">
  25. <div class="zkqy-table-btn" style="margin-bottom: 10px;">
  26. <el-button type="primary" plain @click="add">新增</el-button>
  27. <el-button type="primary" plain @click="edit">修改</el-button>
  28. </div>
  29. <el-table :data="tableData" style="width: 100%" :fit="true" border>
  30. <el-table-column v-if="columns && columns.length > 0" :width="40">
  31. <template slot-scope="scope">
  32. <el-radio class="radio"
  33. :label="scope.row"
  34. v-model="radio"
  35. @change.native="getCurrentRow(scope.row)">
  36. &nbsp;
  37. </el-radio>
  38. </template>
  39. </el-table-column>
  40. <el-table-column
  41. v-for="column in columns"
  42. :key="column.prop"
  43. :prop="column.prop"
  44. :label="column.label"
  45. :width="column.width"
  46. flex="1">
  47. </el-table-column>
  48. <el-table-column label="操作" width="120" align="center" v-if="columns && columns.length > 0">
  49. <template slot-scope="scope">
  50. <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">
  51. 删除
  52. </el-button>
  53. </template>
  54. </el-table-column>
  55. </el-table>
  56. <el-pagination
  57. @size-change="handleSizeChange"
  58. @current-change="handleCurrentChange"
  59. :current-page="currentPage4"
  60. :page-sizes="[2, 5, 10, 15]"
  61. :page-size="100"
  62. layout="total, sizes, prev, pager, next, jumper"
  63. :total="tableList[0].total">
  64. </el-pagination>
  65. </div>
  66. </div>
  67. `,
  68. data() {
  69. return {
  70. zkqyTablePageJson:[{"type":"zkqyTable","field":"Fcgdma2cofgiazc","title":"表格","$required":false,"props":{"addZkqyTableRow":144,"updateZkqyTableRow":145,"pageId":146},"columns":[{"tableName":"stu","tableType":"primary","columnName":"主键","showValue":"id","searchValue":"stu@id"},{"tableName":"stu","tableType":"primary","columnName":"名称","showValue":"name","searchValue":"stu@name"},{"tableName":"stu","tableType":"primary","columnName":"老师id","showValue":"teacher_id","searchValue":"stu@teacher_id"},{"tableName":"stu","tableType":"primary","columnName":"习惯集合","showValue":"habbit_collection","searchValue":"stu@habbit_collection"},{"tableName":"stu","tableType":"primary","columnName":"树id","showValue":"tree_id","searchValue":"stu@tree_id"},{"tableName":"stu","tableType":"primary","columnName":"性别","showValue":"sex","searchValue":"stu@sex"},{"tableName":"stu","tableType":"primary","columnName":"树id2","showValue":"tree_id_two","searchValue":"stu@tree_id_two"},{"tableName":"stu","tableType":"primary","columnName":"穿梭框id集合","showValue":"el_transfer_id","searchValue":"stu@el_transfer_id"},{"tableName":"cls","tableType":"sub","primaryKey":"cls_id","subKey":"id","columnName":"课程名","showValue":"name","searchValue":"cls@name"}],"_fc_id":"id_Fwqsma2cofgib0c","name":"ref_Fk8ema2cofgib1c","display":true,"hidden":false,"_fc_drag_tag":"zkqyTable"}],
  71. tableData: [],
  72. columns: [{"prop":"stu@id","label":"主键"},{"prop":"stu@name","label":"名称"},{"prop":"stu@teacher_id","label":"老师id"},{"prop":"stu@habbit_collection","label":"习惯集合"},{"prop":"stu@tree_id","label":"树id"},{"prop":"stu@sex","label":"性别"},{"prop":"stu@tree_id_two","label":"树id2"},{"prop":"stu@el_transfer_id","label":"穿梭框id集合"},{"prop":"cls@name","label":"课程名"}],
  73. radio: '',
  74. policyData: {},
  75. currentPage4: 1,
  76. tableList: [{
  77. pageId: '',
  78. total: 0,
  79. pageSize: 2,
  80. pageNum: 1
  81. }],
  82. baseUrl: 'http://192.168.10.103:8088/',
  83. headers: {
  84. Accept: 'application/json',
  85. dbname:'tt18',
  86. 'Content-Type': 'application/json'
  87. },
  88. };
  89. },
  90. methods: {
  91. // 方法实现...
  92. add() {
  93. let p = this.zkqyTablePageJson[0]?.props?.addZkqyTableRow
  94. if(p){
  95. this.queryMobileClickAddData(p)
  96. }
  97. },
  98. edit() {
  99. if (!this.radio) {
  100. this.$message.warning("请先选择一行数据");
  101. return;
  102. }
  103. let formId = this.zkqyTablePageJson[0]?.props?.updateZkqyTableRow
  104. let searchId;
  105. let zj = this.zkqyTablePageJson[0].columns.find(item=>item.tableType=="primary")
  106. if(zj.tableName){
  107. let v = zj.tableName+'@id'
  108. searchId = this.radio[v]
  109. }
  110. if(!formId){
  111. this.$message.warning("请配置跳转页面");
  112. return
  113. }else if(!searchId) {
  114. this.$message.warning("id不存在");
  115. }else {
  116. let params = {
  117. formId,
  118. searchId
  119. }
  120. this.queryMobileClickUpdateData(params)
  121. }
  122. },
  123. getCurrentRow(val) {
  124. this.policyData = val;
  125. console.log('this.policyData', this.policyData)
  126. },
  127. handleSizeChange(val) {
  128. this.tableList[0].pageSize = val;
  129. this.getTableLimitInfo({
  130. pageNum: this.tableList[0].pageNum,
  131. pageSize: this.tableList[0].pageSize,
  132. pageId: this.pageId
  133. });
  134. },
  135. handleCurrentChange(val) {
  136. this.tableList[0].pageNum = val;
  137. this.getTableLimitInfo({
  138. pageNum: this.tableList[0].pageNum,
  139. pageSize: this.tableList[0].pageSize,
  140. pageId: this.pageId
  141. });
  142. },
  143. handleDelete(index, row) {
  144. // console.log(row)
  145. // let zj = this.zkqyTablePageJson[0].columns.find(item=>item.tableType=="primary")
  146. // if(zj.tableName){
  147. // let v = zj.tableName+'@id'
  148. // searchId = this.radio[v]
  149. // }
  150. let id = this.zkqyTablePageJson[0]?.columns[0]?.tableName +'@id'
  151. this.$msgbox.confirm('确认删除id为' + row[id] + '这行数据?', '提示', {
  152. confirmButtonText: '确定',
  153. cancelButtonText: '取消',
  154. type: 'warning'
  155. }).then(() => {
  156. this.tableData.splice(index, 1);
  157. this.deleteTableData(row[id], this.pageId );
  158. }).catch(() => {
  159. this.$message.info("已取消删除");
  160. });
  161. },
  162. async deleteTableData(lineId, pageId) {
  163. const endpoint = 'api/mobilePageDesignData/normal/deleteData';
  164. try {
  165. const url = this.baseUrl + endpoint;
  166. const requestBody = {
  167. lineId: lineId,
  168. pageId: pageId
  169. };
  170. const response = await fetch(url, {
  171. method: 'POST',
  172. headers: this.headers,
  173. body: JSON.stringify(requestBody) // 将参数转为JSON字符串
  174. });
  175. if (!response.ok) {
  176. throw new Error('HTTP error! status: ' + response.status);
  177. }
  178. const result = await response.json();
  179. console.log('删除结果:', result);
  180. if (result.code == 200) {
  181. this.$message.success('删除成功');
  182. let {pageId,pageNum,pageSize} =this.tableList[0]
  183. // 删除成功后刷新表格数据
  184. this.getTableLimitInfo({pageId,pageNum,pageSize})
  185. return true;
  186. } else {
  187. this.$message.error(result.message || '删除失败');
  188. return false;
  189. }
  190. } catch (error) {
  191. console.error('删除数据出错:', error);
  192. this.$message.error('删除请求失败: ' + error.message);
  193. throw error;
  194. }
  195. },
  196. async getTableLimitInfo(params = {}) {
  197. const endpoint = 'api/mobilePageDesignData/muti/tableLimitInfo';
  198. await this.fetchGet(endpoint, params, (data) => {
  199. if (data.code === 200) {
  200. this.tableData = data.rows;
  201. this.tableList[0].total = data.total
  202. } else {
  203. console.warn('接口返回非 200 状态:', data);
  204. }
  205. });
  206. },
  207. async queryMobileClickAddData(params = {}) {
  208. let formId = params;
  209. params ={}
  210. let pageId = this.pageId
  211. console.log('pageId',pageId)
  212. const endpoint = 'api/mobilePageDesignData/queryMobileClickAddData/'+ formId;
  213. await this.fetchGet(endpoint , params,(data) => {
  214. if (data.code === 200) {
  215. const decodedHtml = decodeURIComponent(data.data.htmlData);
  216. // 创建全屏 iframe
  217. const iframe = document.createElement('iframe');
  218. iframe.srcdoc = decodedHtml;
  219. iframe.style.width = '100%';
  220. iframe.style.height = '100vh';
  221. iframe.style.border = 'none';
  222. // 清空页面并插入 iframe
  223. document.body.innerHTML = '';
  224. document.body.appendChild(iframe);
  225. // 将 pageId 存储到 localStorage
  226. localStorage.setItem('sharedPageId', pageId);
  227. }
  228. });
  229. },
  230. async queryMobileClickUpdateData(params = {}) {
  231. let formId = params.formId;
  232. let searchId = params.searchId;
  233. params = {}
  234. // 移除指定的 localStorage 键
  235. // localStorage.removeItem('sharedPageId');
  236. const endpoint = 'api/mobilePageDesignData/queryMobileClickUpdateData/'+this.pageId +'/'+formId +'/'+searchId;
  237. await this.fetchGet(endpoint , params,(data) => {
  238. if (data.code === 200) {
  239. const decodedHtml = decodeURIComponent(data.data.htmlData);
  240. const iframe = document.createElement('iframe');
  241. iframe.srcdoc = decodedHtml;
  242. iframe.style.width = '100%';
  243. iframe.style.height = '100vh';
  244. iframe.style.border = 'none';
  245. document.body.innerHTML = '';
  246. document.body.appendChild(iframe);
  247. // 将 pageId 存储到 localStorage
  248. localStorage.setItem('sharedPageId', this.pageId);
  249. }
  250. });
  251. },
  252. async fetchGet(endpoint, params = {}, successCallback) {
  253. try {
  254. // 构建查询字符串
  255. const queryString = Object.keys(params)
  256. .map(key => encodeURIComponent(key) + '=' + encodeURIComponent(params[key]))
  257. .join('&');
  258. // 拼接完整的 URL
  259. const url = this.baseUrl + endpoint + (queryString ? '?' + queryString : '');
  260. // 发起 GET 请求
  261. const response = await fetch(url, {
  262. method: 'GET',
  263. headers: this.headers
  264. });
  265. // 检查响应状态
  266. if (!response.ok) {
  267. throw new Error('HTTP error! status: ' + response.status);
  268. }
  269. // 解析返回的数据
  270. const data = await response.json();
  271. // 调用成功回调函数
  272. if (successCallback && typeof successCallback === 'function') {
  273. successCallback(data);
  274. }
  275. } catch (error) {
  276. console.error('调用接口出错:', error);
  277. throw error; // 抛出错误以便上层捕获
  278. }
  279. }
  280. },
  281. mounted() {
  282. console.log('父组件传递的 options:', this.pageId);
  283. this.tableList[0].pageId = this.pageId
  284. let { pageId, pageNum, pageSize } = this.tableList[0];
  285. this.getTableLimitInfo({ pageId, pageNum, pageSize });
  286. }
  287. };
  288. // 注册组件
  289. Vue.use(ELEMENT);
  290. Vue.use(formCreate);
  291. formCreate.component('zkqyTable', zkqyTable);
  292. new Vue({
  293. el: '#app',
  294. data() {
  295. return {
  296. rule: formCreate.parseJson('[{"type":"zkqyTable","field":"Fcgdma2cofgiazc","title":"表格","$required":false,"props":{"addZkqyTableRow":144,"updateZkqyTableRow":145,"pageId":146},"columns":[{"tableName":"stu","tableType":"primary","columnName":"主键","showValue":"id","searchValue":"stu@id"},{"tableName":"stu","tableType":"primary","columnName":"名称","showValue":"name","searchValue":"stu@name"},{"tableName":"stu","tableType":"primary","columnName":"老师id","showValue":"teacher_id","searchValue":"stu@teacher_id"},{"tableName":"stu","tableType":"primary","columnName":"习惯集合","showValue":"habbit_collection","searchValue":"stu@habbit_collection"},{"tableName":"stu","tableType":"primary","columnName":"树id","showValue":"tree_id","searchValue":"stu@tree_id"},{"tableName":"stu","tableType":"primary","columnName":"性别","showValue":"sex","searchValue":"stu@sex"},{"tableName":"stu","tableType":"primary","columnName":"树id2","showValue":"tree_id_two","searchValue":"stu@tree_id_two"},{"tableName":"stu","tableType":"primary","columnName":"穿梭框id集合","showValue":"el_transfer_id","searchValue":"stu@el_transfer_id"},{"tableName":"cls","tableType":"sub","primaryKey":"cls_id","subKey":"id","columnName":"课程名","showValue":"name","searchValue":"cls@name"}],"_fc_id":"id_Fwqsma2cofgib0c","name":"ref_Fk8ema2cofgib1c","display":true,"hidden":false,"_fc_drag_tag":"zkqyTable"}]'),
  297. options: formCreate.parseJson('{"form":{"inline":false,"hideRequiredAsterisk":false,"showMessage":true,"inlineMessage":false,"labelPosition":"right","labelWidth":"125px","validateOnRuleChange":false,"size":"small","formName":"表格1"},"resetBtn":{"show":false,"innerText":"重置"},"submitBtn":{"show":true,"innerText":"提交"}}'),
  298. formData: {},
  299. api: null,
  300. zkqyData:[],
  301. zkqyUpload:[],
  302. };
  303. },
  304. methods: {
  305. onSubmit(formData){
  306. console.log('submit', formData);
  307. },
  308. async zkqyDataApi(data,type,id){
  309. let zkqyData = this.zkqyData;
  310. if (!zkqyData || zkqyData.length === 0) return;
  311. const headers = {
  312. 'Accept': 'application/json',
  313. 'dbname': 'undefined',
  314. 'Content-Type': 'application/json'
  315. };
  316. try {
  317. let response;
  318. if (type === 'cascader' || type === 'tree') {
  319. // 调用树形接口 POST
  320. const apiUrl = 'undefinedapi/mobilePageDesignData/tree';
  321. console.log('调用树形接口:', apiUrl);
  322. response = await fetch(apiUrl, {
  323. method: 'POST',
  324. headers,
  325. body: JSON.stringify(data)
  326. });
  327. } else {
  328. // 调用下拉框接口 GET
  329. let x = new URLSearchParams(data).toString()
  330. const apiUrl = 'undefinedapi/mobilePageDesignData/dropdown?'+x;
  331. console.log('调用下拉框接口:', apiUrl);
  332. response = await fetch(apiUrl, {
  333. method: 'GET',
  334. headers
  335. });
  336. }
  337. if (!response.ok) {
  338. throw new Error('HTTP error! status:response.status');
  339. }
  340. const result = await response.json();
  341. const targetRule = this.rule.find(item => item._fc_id === id);
  342. if (type === 'tree') {
  343. this.$set(targetRule?.props, 'data', result.data);
  344. }
  345. else if(type === 'cascader'){
  346. this.$set(targetRule.props, 'options', result.data);
  347. }else if(type === 'elTransfer'){
  348. this.$set(targetRule.props, 'data', result.data);
  349. }else {
  350. this.$set(targetRule, 'options', result.data);
  351. }
  352. this.rule =formCreate.parseJson(formCreate.toJson([...this.rule])); // 触发重新渲染
  353. return result;
  354. } catch (error) {
  355. console.error('type接口请求失败:', error);
  356. throw error;
  357. }
  358. },
  359. transformTreeToSingleObject(node) {
  360. if (!node) return node;
  361. // 创建新对象,避免修改原对象
  362. const newNode = {...node};
  363. // 处理 childrenTree
  364. if (Array.isArray(newNode.childrenTree) ){
  365. if (newNode.childrenTree.length > 0) {
  366. // 取第一个元素作为对象
  367. newNode.childrenTree = this.transformTreeToSingleObject(newNode.childrenTree[0]);
  368. } else {
  369. // 空数组转为 null 或 undefined
  370. newNode.childrenTree = null;
  371. }
  372. } else if (newNode.childrenTree) {
  373. // 如果不是数组但存在 childrenTree,递归处理
  374. newNode.childrenTree = this.transformTreeToSingleObject(newNode.childrenTree);
  375. }
  376. return newNode;
  377. },
  378. },
  379. mounted() {
  380. this.rule.forEach(ruleItem => {
  381. if(ruleItem.type=="upload"){
  382. console.log('ruleItem',ruleItem)
  383. console.log('this.rule ',this.rule )
  384. if(ruleItem?.value.length>0){
  385. const processedUrl = 'undefined'.endsWith('/') ?'undefined'.slice(0, -1) : 'undefined'; // 如果 url 最后一个字符是斜杠,则去掉它
  386. console.log('processedUrl',processedUrl)
  387. ruleItem.value = ruleItem.value.map(
  388. item => processedUrl+item
  389. );
  390. }
  391. console.log(' ruleItem.value ', ruleItem.value )
  392. // this.rule =formCreate.parseJson(formCreate.toJson([...this.rule])); // 触发重新渲染
  393. ruleItem.props.onSuccess="[[FORM-CREATE-PREFIX-function onSuccess(res, file){const key='upload_row';const existingData=sessionStorage.getItem(key);let fileList=existingData?JSON.parse(existingData):[];if(!Array.isArray(fileList)){fileList=[];}const newItem={fileName: file.response.fileName, url: file.url};fileList.push(newItem);sessionStorage.setItem(key,JSON.stringify(fileList));}-FORM-CREATE-SUFFIX]]"
  394. }
  395. })
  396. let zkqyData = this.zkqyData
  397. if(zkqyData && zkqyData.length>0){
  398. console.log('[this.rule]',this.rule)
  399. this.rule.forEach(ruleItem => {
  400. const matchedData = zkqyData.find(dataItem => dataItem._fc_id === ruleItem._fc_id);
  401. if (matchedData) {
  402. if (matchedData?.type !== 'cascader' && matchedData?.type !== 'tree') {
  403. resultObj = {
  404. tableName: matchedData?.parentNode?.tableName,
  405. valueName: matchedData?.parentNode?.primaryIdField,
  406. labelName: matchedData?.parentNode?.showValue,
  407. type: matchedData?.type
  408. };
  409. this.zkqyDataApi(resultObj,matchedData?.type,matchedData._fc_id)
  410. }
  411. else {
  412. resultObj = this.transformTreeToSingleObject(matchedData.parentNode);
  413. resultObj.componentType = matchedData?.type
  414. this.zkqyDataApi(resultObj,matchedData?.type,matchedData._fc_id)
  415. }
  416. }
  417. })
  418. }},
  419. })
  420. </script>
  421. </body>
  422. </html>