AssociatedFields.vue 12 KB

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