DatabaseTable.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <!--
  2. * @Author: your name
  3. * @Date: 2024-10-28 17:43:21
  4. * @LastEditTime: 2025-01-03 12:35:03
  5. * @LastEditors: milo-MBP
  6. * @Description: In User Settings Edit
  7. * @FilePath: /performance-test/src/views/performance/components/custonAsCom/DatabaseTable.vue
  8. -->
  9. <template>
  10. <div class="databaseContent">
  11. <template v-if="dialogVisible">
  12. <el-dialog
  13. title="连接服务器"
  14. :visible.sync="dialogVisible"
  15. width="550px"
  16. :before-close="handleClose"
  17. >
  18. <el-form
  19. label-position="right"
  20. label-width="120px"
  21. :model="formLabelAlign"
  22. :rules="rules"
  23. ref="ruleForm"
  24. size="small"
  25. >
  26. <el-form-item label="主机名IP地址:" prop="IP">
  27. <el-input v-model="formLabelAlign.IP"></el-input>
  28. </el-form-item>
  29. <el-form-item label="端口:" prop="host">
  30. <el-input v-model="formLabelAlign.host"></el-input>
  31. </el-form-item>
  32. <el-form-item label="数据库名称:" prop="baseName">
  33. <el-input v-model="formLabelAlign.baseName"></el-input>
  34. </el-form-item>
  35. <el-form-item label="用户名:" prop="username">
  36. <el-input v-model="formLabelAlign.username"></el-input>
  37. </el-form-item>
  38. <el-form-item label="密码:" prop="password">
  39. <el-input
  40. type="password"
  41. v-model="formLabelAlign.password"
  42. show-password
  43. ></el-input>
  44. </el-form-item>
  45. <el-form-item>
  46. <el-button type="primary" @click="submitForm('ruleForm')">
  47. 访问
  48. </el-button>
  49. </el-form-item>
  50. </el-form>
  51. </el-dialog>
  52. </template>
  53. <template v-if="showDialog">
  54. <el-dialog
  55. title="数据库导航器"
  56. :visible.sync="showDialog"
  57. width="550px"
  58. :before-close="handleClose"
  59. >
  60. <el-input
  61. placeholder="输入关键字进行过滤"
  62. v-model="filterText"
  63. ></el-input>
  64. <el-tree
  65. class="filter-tree"
  66. :data="treeData"
  67. show-checkbox
  68. :props="defaultProps"
  69. :check-strictly="false"
  70. :filter-node-method="filterNode"
  71. ref="tree"
  72. >
  73. <!-- :check-strictly="false"
  74. :render-content="renderContent" -->
  75. </el-tree>
  76. <el-row type="flex" class="row-bg" justify="space-between">
  77. <el-col :span="4">
  78. <el-button size="small" @click="handleClose">取消</el-button>
  79. </el-col>
  80. <el-col :span="4">
  81. <el-button size="small" type="primary" @click="loadData"
  82. >加载</el-button
  83. >
  84. </el-col>
  85. </el-row>
  86. </el-dialog>
  87. </template>
  88. </div>
  89. </template>
  90. <script>
  91. import axios from "axios";
  92. import { storeSetData, initDatabase } from "@/utils/indexedDb";
  93. import { mapMutations, mapState } from "vuex";
  94. import { format } from "date-fns";
  95. export default {
  96. props: {
  97. dialogVisible: {
  98. type: Boolean,
  99. default: false,
  100. },
  101. },
  102. data() {
  103. return {
  104. showDialog: false,
  105. formLabelAlign: {
  106. IP: "",
  107. host: "",
  108. baseName: "",
  109. username: "",
  110. password: "",
  111. },
  112. rules: {
  113. IP: { required: true, message: "请输入主机名/IP地址", trigger: "blur" },
  114. host: {
  115. required: true,
  116. message: "请输入端口",
  117. trigger: "blur",
  118. },
  119. baseName: {
  120. required: true,
  121. message: "请输入数据库名称",
  122. trigger: "blur",
  123. },
  124. username: { required: true, message: "请输入用户名", trigger: "blur" },
  125. password: { required: true, message: "请输入密码", trigger: "blur" },
  126. },
  127. defaultProps: {
  128. children: "children",
  129. label: "label",
  130. },
  131. // 转换后的树数据
  132. treeData: [],
  133. filterText: "", // 初始化 filterText
  134. data: [],
  135. };
  136. },
  137. computed: {
  138. ...mapState("dragChart", {
  139. updateTriggerGetData: "updateTriggerGetData",
  140. triggerGetData: "triggerGetData",
  141. }),
  142. },
  143. watch: {
  144. filterText(val) {
  145. this.$refs.tree.filter(val);
  146. },
  147. },
  148. methods: {
  149. ...mapMutations("dragChart", [
  150. "setTriggerGetData",
  151. "setUpdateTriggerGetData",
  152. ]),
  153. handleClose(done) {
  154. this.$confirm("确认关闭?")
  155. .then((_) => {
  156. !this.showDialog
  157. ? this.$emit("closeDialog")
  158. : (this.showDialog = false);
  159. })
  160. .catch((_) => {});
  161. },
  162. // 将原始数据转化为树形数据
  163. initializeTreeData(data) {
  164. // 构建树结构
  165. this.treeData = Object.keys(data).map((tableName) => ({
  166. label: tableName,
  167. children: data[tableName].map((field) => ({
  168. label: field,
  169. field: field,
  170. parentNode: tableName,
  171. })),
  172. }));
  173. },
  174. // 节点过滤方法
  175. filterNode(value, data) {
  176. if (!value) return true; // 如果没有输入过滤文本,则显示所有节点
  177. return data.label.indexOf(value) !== -1; // 如果节点的label包含过滤文本,则返回true
  178. },
  179. // 加载按钮的点击事件
  180. async loadData() {
  181. const selectedNodes = this.$refs.tree.getCheckedNodes();
  182. if (selectedNodes.length <= 0) {
  183. this.$message.warning("请最少选择1表数据");
  184. return;
  185. }
  186. const output = [];
  187. // 使用 Map 分组数据
  188. const grouped = new Map();
  189. selectedNodes.forEach((item) => {
  190. const { parentNode, label } = item;
  191. if (!grouped.has(parentNode)) {
  192. grouped.set(parentNode, []);
  193. }
  194. grouped.get(parentNode).push(label);
  195. });
  196. // 转换为目标结构
  197. grouped.forEach((checkChildNode, parentNode) => {
  198. output.push({ parentNode, checkChildNode });
  199. });
  200. const response = await axios.post(
  201. "/databaseApi/databaseApi/filterTablesData",
  202. {
  203. database: { ...this.formLabelAlign },
  204. filterData: output,
  205. }
  206. );
  207. this.conversionData(response.data);
  208. },
  209. submitForm(formName) {
  210. this.$refs[formName].validate(async (valid) => {
  211. if (valid) {
  212. try {
  213. const response = await axios.get(
  214. "/databaseApi/databaseApi/tables",
  215. {
  216. params: { ...this.formLabelAlign },
  217. }
  218. );
  219. // this.tableFieldMap = response.data;
  220. this.initializeTreeData(response.data);
  221. this.$emit("closeDialog");
  222. this.showDialog = true;
  223. } catch (error) {
  224. this.$message.error(
  225. "数据库连接失败,请查看填写的数据库数据是否有误" + error
  226. );
  227. console.error("Failed to fetch database structure:", error);
  228. }
  229. } else {
  230. return false;
  231. }
  232. });
  233. },
  234. async conversionData(data) {
  235. try {
  236. // 定义最终结果数组
  237. const result = Object.keys(data)
  238. .filter((key) => data[key].length > 0) // 过滤掉空数组的字段
  239. .map((key) => ({
  240. fileData: data[key],
  241. fileId: `${new Date().getTime()}_${key}`, // 添加唯一时间戳和字段标识
  242. fileOldName: `${key}.xlsx`, // 文件原始名称
  243. filename: `${format(new Date(), "yyyyMMdd-HH:mm:ss")}_${key}.xlsx`, // 包含时间戳的文件名
  244. }));
  245. // 初始化数据库
  246. const database = await initDatabase();
  247. // 遍历结果并存储数据
  248. for (const item of result) {
  249. await storeSetData(database, "files", "fileDataArray", item, () => {
  250. this.$message({
  251. type: "success",
  252. message: `关联完成,关联表可在数据表格中查看。`,
  253. });
  254. });
  255. }
  256. // 更新状态和关闭对话框
  257. //更新数据表格数据和自定义图表树形列表
  258. this.setTriggerGetData(true);
  259. this.setUpdateTriggerGetData(true);
  260. this.showDialog = false;
  261. // 重置表单
  262. this.formLabelAlign = {
  263. IP: "",
  264. host: "",
  265. baseName: "",
  266. username: "",
  267. password: "",
  268. };
  269. } catch (error) {
  270. console.error("操作失败:", error);
  271. this.$message({
  272. type: "error",
  273. message: "操作失败,详情请查看控制台。",
  274. });
  275. }
  276. },
  277. },
  278. };
  279. </script>
  280. <style scoped lang="scss">
  281. ::v-deep .el-form-item--small.el-form-item {
  282. margin-bottom: 18px;
  283. }
  284. .row-bg {
  285. margin-top: 30px;
  286. }
  287. .el-tree {
  288. height: 350px;
  289. overflow: scroll;
  290. }
  291. </style>