index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. <template>
  2. <div class="template-textarea">
  3. <div class="rich-editor" v-html="processedContent"></div>
  4. </div>
  5. </template>
  6. <script>
  7. import CKEditor from "ckeditor4-vue"; //@input="handleInput"
  8. import { findData } from "@/api/sourceData";
  9. export default {
  10. name: "app",
  11. emits: ["onUpdateData"],
  12. compnents: {
  13. // ckeditor: CKEditor.component
  14. },
  15. props: {
  16. coms: {
  17. type: Array,
  18. default: () => {
  19. return [];
  20. },
  21. },
  22. currentIndex: {
  23. type: Number,
  24. default: 0,
  25. },
  26. com: {
  27. type: Object,
  28. default: null,
  29. },
  30. },
  31. watch: {
  32. com: {
  33. handler(val) {
  34. if (val && val.content) {
  35. this.updateProcessedContent();
  36. }
  37. /* let _this = this;
  38. if (val == null) return;
  39. if (val.content == undefined || val.content == null) return;
  40. _this.replaceData(val.content).then((res) => {
  41. _this.content = res;
  42. _this.$emit("onUpdateData", this.currentIndex, res);
  43. }); */
  44. },
  45. immediate: true,
  46. deep: true,
  47. },
  48. },
  49. data() {
  50. return {
  51. content: "",
  52. processedContent: "",
  53. };
  54. },
  55. methods: {
  56. async updateProcessedContent() {
  57. this.processedContent = await this.replaceData(this.com.content);
  58. },
  59. async replaceData(data) {
  60. let _this = this;
  61. for (var i = 0; i < _this.com.attrs.length; i++) {
  62. let attrId = _this.com.attrs[i].id;
  63. if (_this.com.attrs[i].type == "variable") {
  64. let item = _this.com.attrs[i];
  65. if (item.data.value_type == 2) {
  66. //多选
  67. let dataItem = item.data.value_item.split(",");
  68. let selectHtml =
  69. '<select id="' +
  70. attrId +
  71. '" data-index="' +
  72. i +
  73. '" class="text-input-box">';
  74. for (var l = 0; l < dataItem.length; l++) {
  75. if (item.content == dataItem[l]) {
  76. selectHtml +=
  77. '<option value="' +
  78. dataItem[l] +
  79. '" selected>' +
  80. dataItem[l] +
  81. "</option>";
  82. } else {
  83. selectHtml +=
  84. '<option value="' +
  85. dataItem[l] +
  86. '">' +
  87. dataItem[l] +
  88. "</option>";
  89. }
  90. }
  91. selectHtml += "</select>";
  92. data = data.replace("{{" + item.id + "}}", selectHtml);
  93. } else {
  94. //文本
  95. data = data.replace(
  96. "{{" + attrId + "}}",
  97. /* `<input type="text" class="text-input-box" data-index="${i}" value="${_this.com.attrs[i].content}" @input="updateContent('${_this.com.attrs[i].id}', $event)" id="${attrId}">`, */
  98. '<input type="text" ref="input_' +
  99. attrId +
  100. '" name="' +
  101. _this.com.attrs[i].name +
  102. '" id="' +
  103. attrId +
  104. '" data-index="' +
  105. i +
  106. '" class="text-input-box" value="' +
  107. _this.com.attrs[i].content +
  108. '">'
  109. );
  110. }
  111. }else if(_this.com.attrs[i].type == "variableNull"){
  112. let item = _this.com.attrs[i];
  113. data = data.replace(
  114. "{{" + attrId + "}}",
  115. '<input type="text" ref="input_' +
  116. attrId +
  117. '" name="' +
  118. _this.com.attrs[i].name +
  119. '" id="' +
  120. attrId +
  121. '" data-index="' +
  122. i +
  123. '" class="text-input-boxs auto-width" value="' +
  124. _this.com.attrs[i].content +
  125. '">'
  126. );
  127. } else if (_this.com.attrs[i].type == "ProductAttr") {
  128. //处理产品属性值
  129. let item = _this.com.attrs[i];
  130. let prodAttrId = item.id + "_" + i;
  131. if (item.content == "") {
  132. item.content = item.attrs.value;
  133. }
  134. if (item.attrs.type == 1) {
  135. //输入框
  136. data = data.replace(
  137. "{{" + item.id + "}}",
  138. '<input type="text" id="' +
  139. prodAttrId +
  140. '" data-index="' +
  141. i +
  142. '" class="text-input-box" value="' +
  143. item.content +
  144. '">'
  145. );
  146. } else {
  147. //选择框
  148. let dataItem = item.attrs.valueItems.split(",");
  149. let selectHtml =
  150. '<select id="' +
  151. prodAttrId +
  152. '" data-index="' +
  153. i +
  154. '" class="text-input-box">';
  155. for (var l = 0; l < dataItem.length; l++) {
  156. if (item.content == dataItem[l]) {
  157. selectHtml +=
  158. '<option value="' +
  159. dataItem[l] +
  160. '" selected>' +
  161. dataItem[l] +
  162. "</option>";
  163. } else {
  164. selectHtml +=
  165. '<option value="' +
  166. dataItem[l] +
  167. '">' +
  168. dataItem[l] +
  169. "</option>";
  170. }
  171. }
  172. selectHtml += "</select>";
  173. data = data.replace("{{" + item.id + "}}", selectHtml);
  174. }
  175. } else if (_this.com.attrs[i].type == "formual") {
  176. //// console.log('attrs',_this.com.attrs[i]);
  177. //处理计算公式 不处理
  178. let formual = await _this.analysisFormual(_this.com.attrs[i]);
  179. formual = await _this.getRemote(formual);
  180. _this.com.attrs[i].content = eval(formual);
  181. data = data.replace("{{" + attrId + "}}", eval(formual));
  182. } else if (_this.com.attrs[i].type == "sourceData") {
  183. let result = await _this.getRemote1(_this.com.attrs[i].formula);
  184. data = data.replace("{{" + attrId + "}}", result);
  185. } else if (_this.com.attrs[i].type == "Directory") {
  186. const directoryContent = _this.com.attrs[i].number+'. '+_this.com.attrs[i].content;;
  187. const level = _this.com.attrs[i].level || 1; // 默认为1级目录
  188. const attrId = _this.com.attrs[i].id;
  189. // 创建一个更灵活的正则表达式模式
  190. const directoryRegex = new RegExp(`{{\\s*${attrId}\\s*}}`, "g");
  191. // 替换内容,直接在标题标签上应用类名
  192. data = data.replace(directoryRegex, (match, offset, string) => {
  193. // 根据级别创建适当的HTML标签
  194. const tag = `h${Math.min(level, 6)}`; // 限制最大级别为h6
  195. const className = `directory-level-${level}`;
  196. return `<${tag} class="${className}">${directoryContent}</${tag}>`;
  197. });
  198. /* const directoryContent = _this.com.attrs[i].content;
  199. const attrId = _this.com.attrs[i].id;
  200. // Create a more flexible regex pattern
  201. const directoryRegex = new RegExp(`{{\\s*${attrId}\\s*}}`, "g");
  202. // Replace the content, preserving surrounding HTML tags
  203. data = data.replace(directoryRegex, (match, offset, string) => {
  204. // Check if the match is inside a tag
  205. const precedingText = string.substring(0, offset);
  206. const followingText = string.substring(offset + match.length);
  207. const precedingTag = precedingText.match(/<([^>]+)>$/);
  208. const followingCloseTag = followingText.match(/^<\/([^>]+)>/);
  209. if (
  210. precedingTag &&
  211. followingCloseTag &&
  212. precedingTag[1] === followingCloseTag[1]
  213. ) {
  214. // If it's inside matching tags, replace the entire element
  215. return `<h1>${directoryContent}</h1>`;
  216. } else {
  217. // Otherwise, just replace the placeholder
  218. return directoryContent;
  219. }
  220. }); */
  221. } else {
  222. //处理常量及其它
  223. data = data.replace("{{" + attrId + "}}", _this.com.attrs[i].content);
  224. }
  225. }
  226. this.$nextTick(() => {
  227. this.addInputListeners()
  228. this.autoWidths()
  229. });
  230. return data;
  231. },
  232. addInputListeners() {
  233. // 使用事件委托来处理所有的 .text-input-box 元素
  234. this.$el.addEventListener("input", this.adjustAutoWidth, true);
  235. },
  236. autoWidths(){
  237. const inputs = this.$el.querySelectorAll(".text-input-boxs");
  238. inputs.forEach((input) => this.adjustAutoWidth({ target: input }));
  239. },
  240. adjustAutoWidth(event){
  241. if (event.target.classList.contains("text-input-boxs")) {
  242. const input = event.target;
  243. const sizeCalculator = document.createElement("span");
  244. sizeCalculator.className = "size-calculator";
  245. sizeCalculator.textContent = input.value || input.placeholder || "0";
  246. document.body.appendChild(sizeCalculator);
  247. const styles = window.getComputedStyle(input);
  248. sizeCalculator.style.font = styles.font;
  249. sizeCalculator.style.fontSize = styles.fontSize;
  250. sizeCalculator.style.fontWeight = styles.fontWeight;
  251. sizeCalculator.style.letterSpacing = styles.letterSpacing;
  252. const width = sizeCalculator.offsetWidth;
  253. input.style.width = `${width + 10}px`; // Add some padding
  254. document.body.removeChild(sizeCalculator);
  255. }
  256. },
  257. async analysisFormual(attrs) {
  258. let _this = this;
  259. // console.log("开始分析公式:", attrs.formula);
  260. var pattern = /(\[.*?\]){3}/;
  261. var formual = attrs.formula;
  262. var reg = new RegExp(pattern);
  263. while (true) {
  264. var items = formual.match(reg);
  265. if (items == null) break;
  266. let itemName = items[0];
  267. // console.log("处理项:", itemName);
  268. try {
  269. let data = await _this.getFormualData(itemName);
  270. // console.log(`获取到的数据: ${itemName} = ${data}`);
  271. if (data === null || data === undefined || isNaN(data)) {
  272. console.warn(`获取到的数据无效: ${itemName}`);
  273. formual = formual.replace(itemName, "(0)");
  274. } else {
  275. formual = formual.replace(itemName, `(${parseFloat(data)})`);
  276. }
  277. } catch (error) {
  278. console.error(`处理 ${itemName} 时出错:`, error);
  279. formual = formual.replace(itemName, "(0)");
  280. }
  281. }
  282. return formual;
  283. },
  284. async getFormualData(formualItem) {
  285. let _this = this;
  286. // console.log("开始获取公式数据:", formualItem);
  287. var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
  288. var reg = new RegExp(pattern);
  289. let items = formualItem.match(reg);
  290. // console.log("解析结果:", items);
  291. let calResult = 0;
  292. if (items && items[1] == "T") {
  293. calResult = await _this.getModuleData(items[2], items[3]);
  294. } else {
  295. console.warn("无法解析公式项:", formualItem);
  296. }
  297. // console.log("计算结果:", calResult);
  298. return calResult;
  299. },
  300. updateContent(id, event) {
  301. const attr = this.com.attrs.find((attr) => attr.id === id);
  302. if (attr) {
  303. attr.content = event.target.value;
  304. }
  305. },
  306. /* async replaceData(data) {
  307. let _this = this;
  308. for (var i = 0; i < _this.com.attrs.length; i++) {
  309. let attrId = _this.com.attrs[i].id;
  310. if (_this.com.attrs[i].type == "formula") {
  311. let formula = await _this.analysisformula(_this.com.attrs[i]);
  312. formula = await _this.getRemote(formula);
  313. let evalResult = eval(formula);
  314. if (!isNaN(evalResult)) {
  315. data = data.replace("{{" + attrId + "}}", evalResult);
  316. }
  317. } else if (_this.com.attrs[i].type == "sourceData") {
  318. let result = await _this.getRemote1(_this.com.attrs[i].formula);
  319. if (!isNaN(result)) {
  320. data = data.replace("{{" + attrId + "}}", result);
  321. }
  322. } else if (_this.com.attrs[i].type == "Directory") {
  323. //处理目录
  324. data = data.replace(
  325. "<p>{{" + attrId + "}}</p>",
  326. "<h1>" + _this.com.attrs[i].content + "</h1>"
  327. );
  328. data = data.replace(
  329. "<div>{{" + attrId + "}}</div>",
  330. "<h1>" + _this.com.attrs[i].content + "</h1>"
  331. );
  332. data = data.replace(
  333. "<span>{{" + attrId + "}}</span>",
  334. "<h1>" + _this.com.attrs[i].content + "</h1>"
  335. );
  336. } else {
  337. data = data.replace("{{" + attrId + "}}", _this.com.attrs[i].content);
  338. }
  339. }
  340. return data;
  341. }, */
  342. //分析公式
  343. async analysisformula(attrs) {
  344. let _this = this;
  345. var pattern = /(\[.*?\]){3}/;
  346. var formula = attrs.formula;
  347. var reg = new RegExp(pattern);
  348. while (true) {
  349. var items = formula.match(reg);
  350. if (items == null) break;
  351. let itemName = items[0];
  352. let data = await _this.getformulaData(itemName);
  353. data = await _this.getRemote(data);
  354. formula = formula.replace(itemName, "(" + parseFloat(data) + ")");
  355. }
  356. return formula;
  357. },
  358. async getformulaData(formulaItem) {
  359. let _this = this;
  360. var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
  361. var reg = new RegExp(pattern);
  362. let items = formulaItem.match(reg);
  363. let calResult = 0;
  364. if (items[1] == "T") {
  365. //表示本地模板数据
  366. calResult = await _this.getModuleData(items[2], items[3]);
  367. }
  368. return calResult;
  369. },
  370. async getRemote(formula) {
  371. let _this = this;
  372. var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
  373. var reg = new RegExp(pattern);
  374. while (true) {
  375. let items = formula.match(reg);
  376. if (items == null) break;
  377. if (items[1] == "R") {
  378. //表示获取远程数据
  379. var dataIndex = items[4];
  380. dataIndex = items[4].split(",");
  381. let calResult = await _this.getRemoteData(
  382. items[2],
  383. items[3],
  384. dataIndex[0],
  385. dataIndex[1]
  386. );
  387. let itemName = items[0];
  388. formula = formula.replace(
  389. itemName,
  390. "(" + parseFloat(calResult) + ")"
  391. );
  392. }
  393. }
  394. return formula;
  395. },
  396. async getRemote1(formula) {
  397. let _this = this;
  398. var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
  399. var reg = new RegExp(pattern);
  400. while (true) {
  401. let items = formula.match(reg);
  402. if (items == null) break;
  403. if (items[1] == "R") {
  404. //表示获取远程数据
  405. var dataIndex = items[4];
  406. dataIndex = items[4].split(",");
  407. let calResult = await _this.getRemoteData(
  408. items[2],
  409. items[3],
  410. dataIndex[0],
  411. dataIndex[1]
  412. );
  413. let itemName = items[0];
  414. formula = formula.replace(itemName, parseFloat(calResult));
  415. }
  416. }
  417. return formula;
  418. },
  419. //获取远程数据
  420. async getRemoteData(code, sheet, row, col) {
  421. debugger;
  422. let _this = this;
  423. let result = 0;
  424. let par = {
  425. code: code,
  426. sheetName: sheet,
  427. row: row,
  428. col: col,
  429. };
  430. let res = await findData(par);
  431. if (res.status == 200) {
  432. console.log("result:", res.data);
  433. let dataResult = parseFloat(res.data.result);
  434. if (!isNaN(dataResult)) {
  435. return dataResult;
  436. }
  437. }
  438. return 0;
  439. },
  440. //获取本地文档模块数据
  441. async getModuleData(code, attrName) {
  442. let _this = this;
  443. // console.log(`尝试获取模块数据: code=${code}, attrName=${attrName}`);
  444. // console.log("当前 coms:", _this.coms);
  445. let item = _this.coms.filter((o) => o.name == code);
  446. // console.log(`找到的模块:`, item);
  447. if (item.length > 0) {
  448. let attr = item[0].attrs.filter((o) => o.name == attrName);
  449. // console.log(`找到的属性:`, attr);
  450. if (attr.length > 0) {
  451. // console.log(`返回的值:`, attr[0].content);
  452. return parseFloat(attr[0].content);
  453. }
  454. }
  455. // console.log("未找到匹配的模块或属性,返回 0");
  456. return 0;
  457. },
  458. },
  459. };
  460. </script>
  461. <style lang="scss">
  462. @import "./index.scss";
  463. </style>