AssociatedFields.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <template>
  2. <div class="global-variable">
  3. <el-row type="flex" class="row-bg" justify="end">
  4. <el-button type="primary" @click="handleDrawer">新建关联</el-button>
  5. </el-row>
  6. <el-table
  7. height="600"
  8. :data="relatedFieldsData || []"
  9. border
  10. style="width: 100%"
  11. >
  12. <el-table-column prop="tableFileName1" label="关联表1"> </el-table-column>
  13. <el-table-column prop="tableFileName2" label="关联表2"> </el-table-column>
  14. <el-table-column prop="tableFileName1" label="表1关联字段" align="center">
  15. <template slot-scope="scope">
  16. <div v-for="(item, ind) in scope.row.relatedFields?.formSelection1">
  17. <span style="display: inline-block">{{ item.label }}</span>
  18. </div>
  19. </template>
  20. </el-table-column>
  21. <el-table-column prop="address" label="" align="center">
  22. <template slot-scope="scope">
  23. <i
  24. style="font-size: 24px; color: #ffc107"
  25. class="el-icon-connection"
  26. ></i>
  27. </template>
  28. </el-table-column>
  29. <el-table-column prop="tableFileName2" label="表2关联字段" align="center">
  30. <template slot-scope="scope">
  31. <div v-for="(item, ind) in scope.row.relatedFields?.formSelection2">
  32. <span>{{ item.label }}</span>
  33. </div>
  34. </template>
  35. </el-table-column>
  36. </el-table>
  37. <el-drawer
  38. title="新建关联"
  39. :visible.sync="drawer"
  40. direction="rtl"
  41. width="50%"
  42. :before-close="handleClose"
  43. >
  44. <el-card class="box-card">
  45. <div slot="header" class="clearfix">
  46. <el-button
  47. type="primary"
  48. icon="el-icon-circle-plus-outline"
  49. @click="
  50. formSelection1.push({ label: '', fileData: [], id: '' });
  51. formSelection2.push({ label: '', fileData: [], id: '' });
  52. "
  53. >添加关联字段</el-button
  54. >
  55. <el-form
  56. :model="ruleForm"
  57. :rules="rules"
  58. ref="ruleForm"
  59. class="demo-ruleForm"
  60. label-position="left"
  61. >
  62. <el-form-item label="关联表名" prop="name">
  63. <el-input v-model="ruleForm.name"></el-input>
  64. </el-form-item>
  65. </el-form>
  66. </div>
  67. <div class="flexs">
  68. <div class="flexsCenter">
  69. <div style="color: #928c8c; margin: 0 0 10px 0">关联表1</div>
  70. <el-select
  71. v-model="dataChart1"
  72. placeholder="请选择"
  73. @change="handleSelectData1"
  74. >
  75. <el-option
  76. v-for="item in options"
  77. :key="item.id"
  78. :label="item.label"
  79. :value="item.id"
  80. >
  81. </el-option>
  82. </el-select>
  83. <template v-for="(item, ind) in formSelection1">
  84. <el-select
  85. style="margin: 5px 0"
  86. :key="ind + 'select'"
  87. v-model="formSelection1[ind].id"
  88. placeholder="请先进行数据配置"
  89. >
  90. <el-option
  91. v-for="item in tableDataChart1"
  92. :label="item.label"
  93. :value="item.id"
  94. :key="item.id"
  95. ></el-option>
  96. </el-select>
  97. </template>
  98. </div>
  99. <div class="flexsCenter">
  100. <div style="color: #928c8c; margin: 0 0 10px 0">关联表2</div>
  101. <el-select
  102. v-model="dataChart2"
  103. placeholder="请选择"
  104. @change="handleSelectData2"
  105. >
  106. <el-option
  107. v-for="item in options"
  108. :key="item.id"
  109. :label="item.label"
  110. :value="item.id"
  111. >
  112. </el-option>
  113. </el-select>
  114. <template v-for="(item, ind) in formSelection2">
  115. <el-select
  116. style="margin: 5px 0"
  117. :key="ind + 'select'"
  118. v-model="formSelection2[ind].id"
  119. placeholder="请先进行数据配置"
  120. >
  121. <el-option
  122. v-for="item in tableDataChart2"
  123. :label="item.label"
  124. :value="item.id"
  125. :key="item.id"
  126. ></el-option>
  127. </el-select>
  128. </template>
  129. </div>
  130. </div>
  131. </el-card>
  132. <el-row type="flex" class="row-bg" justify="center">
  133. <el-button
  134. type="primary"
  135. @click="submitAssociated('ruleForm')"
  136. style="width: 200px"
  137. >确定关联</el-button
  138. >
  139. </el-row>
  140. </el-drawer>
  141. </div>
  142. </template>
  143. <script>
  144. import {
  145. getDataFromIndexedDB,
  146. checkObjectStoreExists,
  147. storeSetData,
  148. initDatabase,
  149. } from "@/utils/indexedDb";
  150. import { mapMutations, mapState } from "vuex";
  151. export default {
  152. data() {
  153. return {
  154. ruleForm: {
  155. name: "",
  156. },
  157. rules: {
  158. name: [{ required: true, message: "请输入表名称", trigger: "blur" }],
  159. },
  160. drawer: false,
  161. options: [],
  162. dataChart1: [],
  163. dataChart2: [],
  164. tableFileName1: "",
  165. tableFileName2: "",
  166. formSelection1: [{ label: "", fileData: [], id: "" }],
  167. formSelection2: [{ label: "", fileData: [], id: "" }],
  168. tableDataChart1: [],
  169. tableDataChart2: [],
  170. };
  171. },
  172. computed: {
  173. ...mapState("dragChart", {
  174. relatedFieldsData: "relatedFieldsData",
  175. }),
  176. },
  177. methods: {
  178. ...mapMutations("dragChart", [
  179. "setRelatedFieldsData",
  180. "setTriggerGetData",
  181. "setUpdateTriggerGetData",
  182. ]),
  183. async saveDatas(data) {
  184. await initDatabase()
  185. .then((database) => {
  186. // 调用 storeSetData 方法
  187. let fileData = {
  188. filename: this.ruleForm.name + "关联表",
  189. fileData: data,
  190. fileOldName: this.ruleForm.name + "关联表",
  191. fileId:
  192. new Date().getTime() + "_" + Math.floor(Math.random() * 1000),
  193. };
  194. storeSetData(database, "files", "fileDataArray", fileData, () => {
  195. this.setRelatedFieldsData({
  196. tableFileName1: this.tableFileName1,
  197. tableFileName2: this.tableFileName2,
  198. relatedFields: {
  199. formSelection1: this.formSelection1,
  200. formSelection2: this.formSelection2,
  201. },
  202. });
  203. this.setTriggerGetData(true);
  204. this.setUpdateTriggerGetData(true);
  205. this.ruleForm.name = "";
  206. this.formSelection1 = [{ label: "", fileData: [], id: "" }];
  207. this.formSelection2 = [{ label: "", fileData: [], id: "" }];
  208. this.drawer = false;
  209. this.$message({
  210. type: "success",
  211. message: `关联完成,关联表可在数据表格中查看。`,
  212. });
  213. });
  214. })
  215. .catch((error) => {
  216. console.error("数据库初始化失败,无法继续存储数据。", error);
  217. });
  218. },
  219. filterDataRecursively(filterNodeData, ind) {
  220. if (ind >= this.formSelection2.length) {
  221. // 终止条件:当 ind 超过 formSelection2 长度时,返回当前的 filterNodeData
  222. return filterNodeData;
  223. }
  224. const data = [];
  225. filterNodeData.forEach((fileData1) => {
  226. const result = this.formSelection2[ind].fileData.find((fileData2) => {
  227. return (
  228. fileData1[this.formSelection1[ind].label] !== undefined &&
  229. fileData2[this.formSelection2[ind].label] !== undefined &&
  230. fileData1[this.formSelection1[ind].label] + "" ===
  231. fileData2[this.formSelection2[ind].label] + ""
  232. );
  233. });
  234. if (result) {
  235. data.push({
  236. ...fileData1,
  237. ...result,
  238. });
  239. }
  240. });
  241. // 递归调用并返回筛选结果
  242. return this.filterDataRecursively(data, ind + 1);
  243. },
  244. submitAssociated(formName) {
  245. this.$refs[formName].validate((valid) => {
  246. if (valid) {
  247. // 初始化表格数据
  248. this.tableDataChart1.forEach((item) => {
  249. this.formSelection1.forEach((val) => {
  250. if (val.id === item.id) {
  251. val.fileData = item.fileData;
  252. val.label = item.label;
  253. }
  254. });
  255. });
  256. this.tableDataChart2.forEach((item) => {
  257. this.formSelection2.forEach((val) => {
  258. if (val.id === item.id) {
  259. val.fileData = item.fileData;
  260. val.label = item.label;
  261. }
  262. });
  263. });
  264. if (
  265. this.formSelection1[0].fileData.length <= 0 ||
  266. this.formSelection2[0].fileData.length <= 0
  267. ) {
  268. this.$message({
  269. type: "warning",
  270. message: `至少需要关联1组字段。`,
  271. });
  272. return;
  273. }
  274. // 初步过滤数据
  275. let filterNodeData = [];
  276. this.formSelection1.forEach((fileAttribut1, ind) => {
  277. fileAttribut1.fileData.forEach((fileData1) => {
  278. if (ind === 0) {
  279. const result = this.formSelection2[ind].fileData.find(
  280. (fileData2) => {
  281. return (
  282. fileData1[fileAttribut1.label] !== undefined &&
  283. fileData2[this.formSelection2[ind].label] !== undefined &&
  284. fileData1[fileAttribut1.label] + "" ===
  285. fileData2[this.formSelection2[ind].label] + ""
  286. );
  287. }
  288. );
  289. if (result) {
  290. filterNodeData.push({
  291. ...fileData1,
  292. ...result,
  293. });
  294. }
  295. }
  296. });
  297. });
  298. // 递归筛选
  299. filterNodeData = this.filterDataRecursively(filterNodeData, 1);
  300. this.saveDatas(filterNodeData);
  301. } else {
  302. console.log("error submit!!");
  303. return false;
  304. }
  305. });
  306. // console.log(filterNodeData, "filterNodeData");
  307. },
  308. //select 选择
  309. handleSelectData1() {
  310. const obj = this.options.find((item) => item.id === this.dataChart1);
  311. this.tableFileName1 = obj.fileOldName;
  312. this.tableDataChart1 = obj.children;
  313. this.formSelection1 = [{ label: "", fileData: [], id: "" }];
  314. },
  315. handleSelectData2() {
  316. const obj = this.options.find((item) => item.id === this.dataChart2);
  317. this.tableFileName2 = obj.fileOldName;
  318. this.tableDataChart2 = obj.children;
  319. this.formSelection2 = [{ label: "", fileData: [], id: "" }];
  320. },
  321. handleClose(done) {
  322. this.$confirm("确认关闭?")
  323. .then((_) => {
  324. done();
  325. })
  326. .catch((_) => {});
  327. },
  328. async getIndexDbData() {
  329. const jsonData = await getDataFromIndexedDB();
  330. this.options = jsonData.map((item) => {
  331. return {
  332. label: item.filename,
  333. fileOldName: item.fileOldName,
  334. id: item.fileId,
  335. children: [...Object.keys(item.fileData[0])].map((val) => ({
  336. label: val,
  337. id: item.fileId + val,
  338. fileData: item.fileData,
  339. })),
  340. };
  341. });
  342. },
  343. handleDrawer() {
  344. this.drawer = true;
  345. //判断indexedDb中是否存在这个数据表
  346. checkObjectStoreExists("FileDataDB", "files")
  347. .then((exists) => {
  348. if (exists) {
  349. // console.log("对象存储 'files' 存在!");
  350. this.getIndexDbData();
  351. } else {
  352. this.loading = false;
  353. // console.log("对象存储 'files' 不存在!");
  354. }
  355. })
  356. .catch((error) => {
  357. console.error("检查对象存储时出错:", error);
  358. });
  359. },
  360. },
  361. };
  362. </script>
  363. <style scoped lang="scss">
  364. // ::v-deep .global-variable {
  365. // height: 100% !important;
  366. // overflow: scroll !important;
  367. // }
  368. .row-bg {
  369. margin: 10px 0;
  370. }
  371. .box-card {
  372. width: 90%;
  373. margin: 0 auto;
  374. margin-bottom: 20px;
  375. }
  376. ::v-deep .el-drawer {
  377. width: 50% !important;
  378. }
  379. .flexs {
  380. display: flex;
  381. justify-content: space-between;
  382. .flexsCenter {
  383. display: flex;
  384. flex-direction: column;
  385. ::v-deep .el-input--suffix .el-input__inner {
  386. width: 250px;
  387. }
  388. }
  389. }
  390. </style>