@pixel-shell/elpis 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/.eslintgnore +1 -0
  2. package/.eslintrc +55 -0
  3. package/README.md +194 -0
  4. package/app/controller/base.js +40 -0
  5. package/app/controller/project.js +56 -0
  6. package/app/controller/view.js +18 -0
  7. package/app/extend/logger.js +37 -0
  8. package/app/middleware/api-params-verify.js +71 -0
  9. package/app/middleware/api-sign-verify.js +32 -0
  10. package/app/middleware/error-handler.js +33 -0
  11. package/app/middleware/project-handler.js +27 -0
  12. package/app/middleware.js +31 -0
  13. package/app/pages/asserts/custom.css +12 -0
  14. package/app/pages/boot.js +47 -0
  15. package/app/pages/common/curl.js +88 -0
  16. package/app/pages/common/utils.js +2 -0
  17. package/app/pages/dashboard/complex-view/header-view/complex-view/sub-menu/sub-menu.vue +17 -0
  18. package/app/pages/dashboard/complex-view/header-view/header-view.vue +129 -0
  19. package/app/pages/dashboard/complex-view/iframe-view/iframe-view.vue +43 -0
  20. package/app/pages/dashboard/complex-view/schema-view/complex-view/search-panel/search-panel.vue +37 -0
  21. package/app/pages/dashboard/complex-view/schema-view/complex-view/table-panel/table-panel.vue +114 -0
  22. package/app/pages/dashboard/complex-view/schema-view/components/component-config.js +22 -0
  23. package/app/pages/dashboard/complex-view/schema-view/components/create-form/create-form.vue +85 -0
  24. package/app/pages/dashboard/complex-view/schema-view/components/detail-panel/detail-panel.vue +92 -0
  25. package/app/pages/dashboard/complex-view/schema-view/components/edit-form/edit-form.vue +106 -0
  26. package/app/pages/dashboard/complex-view/schema-view/hook/schema.js +123 -0
  27. package/app/pages/dashboard/complex-view/schema-view/schema-view.vue +88 -0
  28. package/app/pages/dashboard/complex-view/sider-view/complex-view/sub-menu/sub-menu.vue +18 -0
  29. package/app/pages/dashboard/complex-view/sider-view/sider-view.vue +117 -0
  30. package/app/pages/dashboard/dashboard.vue +89 -0
  31. package/app/pages/dashboard/entry.dashboard.js +42 -0
  32. package/app/pages/store/index.js +5 -0
  33. package/app/pages/store/menu.js +57 -0
  34. package/app/pages/store/project.js +15 -0
  35. package/app/pages/widgets/header-container/asserts/avatar.png +0 -0
  36. package/app/pages/widgets/header-container/asserts/logo.png +0 -0
  37. package/app/pages/widgets/header-container/header-container.vue +102 -0
  38. package/app/pages/widgets/schema-form/complex-view/input/input.vue +129 -0
  39. package/app/pages/widgets/schema-form/complex-view/input-number/input-number.vue +130 -0
  40. package/app/pages/widgets/schema-form/complex-view/select/select.vue +116 -0
  41. package/app/pages/widgets/schema-form/form-item-config.js +23 -0
  42. package/app/pages/widgets/schema-form/schema-form.vue +121 -0
  43. package/app/pages/widgets/schema-search-bar/complex-view/date-range/date-range.vue +41 -0
  44. package/app/pages/widgets/schema-search-bar/complex-view/dynamic-select/dynamic-select.vue +51 -0
  45. package/app/pages/widgets/schema-search-bar/complex-view/input/input.vue +34 -0
  46. package/app/pages/widgets/schema-search-bar/complex-view/select/select.vue +36 -0
  47. package/app/pages/widgets/schema-search-bar/schema-search-bar.vue +121 -0
  48. package/app/pages/widgets/schema-search-bar/search-item-config.js +27 -0
  49. package/app/pages/widgets/schema-table/schema-table.vue +227 -0
  50. package/app/pages/widgets/sider-container/sider-container.vue +29 -0
  51. package/app/public/static/logo.png +0 -0
  52. package/app/public/static/normalize.css +241 -0
  53. package/app/router/project.js +6 -0
  54. package/app/router/view.js +8 -0
  55. package/app/router-schema/project.js +30 -0
  56. package/app/service/base.js +10 -0
  57. package/app/service/project.js +40 -0
  58. package/app/view/entry.tpl +25 -0
  59. package/app/webpack/build.js +18 -0
  60. package/app/webpack/config/webpack.base.js +234 -0
  61. package/app/webpack/config/webpack.dev.js +58 -0
  62. package/app/webpack/config/webpack.prod.js +113 -0
  63. package/app/webpack/dev.js +60 -0
  64. package/app/webpack/libs/blank.js +1 -0
  65. package/app/webpack/prod.js +22 -0
  66. package/config/config.default.js +3 -0
  67. package/docs/dashboard-mode.js +141 -0
  68. package/elpis-core/env.js +16 -0
  69. package/elpis-core/index.js +70 -0
  70. package/elpis-core/loader/config.js +51 -0
  71. package/elpis-core/loader/controller.js +71 -0
  72. package/elpis-core/loader/extend.js +61 -0
  73. package/elpis-core/loader/middleware.js +69 -0
  74. package/elpis-core/loader/roter-schema.js +54 -0
  75. package/elpis-core/loader/router.js +42 -0
  76. package/elpis-core/loader/service.js +70 -0
  77. package/index.js +35 -0
  78. package/model/index.js +86 -0
  79. package/package.json +92 -0
  80. package/test/controller/project.test.js +194 -0
@@ -0,0 +1,88 @@
1
+ const md5 = require("md5");
2
+ const axios = require("axios");
3
+ import { ElMessage } from "element-plus";
4
+
5
+ /**
6
+ * 前端封装的 curl 方法
7
+ * @param {options} 请求参数
8
+ */
9
+ const curl = ({
10
+ url, // 请求地址
11
+ method = "post", // 请求方法
12
+ headers = {}, // 请求头
13
+ query = {}, // url query 参数
14
+ data = {}, // post body 参数
15
+ responseType = "json", // 响应类型
16
+ timeout = 10000, // 请求超时时间
17
+ errorMessage = "请求失败", // 错误信息
18
+ }) => {
19
+ // 处理签名
20
+ const signKey = "hgy3ghj5gyu03ghjk2ghje3kgu4ghj";
21
+ const st = Date.now(); // 当前时间戳
22
+ const signature = md5(`${signKey}_${st}`);
23
+
24
+ const dtoHeaders = {
25
+ ...headers,
26
+ s_t: st,
27
+ s_sign: signature,
28
+ };
29
+ if (url.indexOf("/api/proj/") > -1 && window.projKey) {
30
+ dtoHeaders.proj_key = window.projKey;
31
+ }
32
+ // 构造请求参数(把参数转化为 axios 请求参数)
33
+ const ajaxSetting = {
34
+ url,
35
+ method,
36
+ params: query,
37
+ data,
38
+ responseType,
39
+ timeout,
40
+ headers: dtoHeaders,
41
+ };
42
+
43
+ return axios
44
+ .request(ajaxSetting)
45
+ .then((response) => {
46
+ const resData = response.data || {};
47
+
48
+ // 后端API返回格式
49
+ const { success, message, code, data } = resData;
50
+
51
+ // 处理失败返回
52
+ if (!success) {
53
+ if (code === 442) {
54
+ ElMessage.error("请求参数异常");
55
+ } else if (code === 445) {
56
+ ElMessage.error("请求不合法");
57
+ } else if (code === 446) {
58
+ console.log("缺少项目必要参数");
59
+ ElMessage.error("缺少项目必要参数");
60
+ } else if (code === 50000) {
61
+ ElMessage.error(message);
62
+ } else {
63
+ ElMessage.error(errorMessage);
64
+ }
65
+ return Promise.resolve({ success, message, code });
66
+ }
67
+ // 处理成功返回
68
+ return Promise.resolve({
69
+ success,
70
+ data,
71
+ message,
72
+ metadata: resData.metadata,
73
+ });
74
+ })
75
+ .catch((error) => {
76
+ const { message } = error;
77
+
78
+ if (message.match(/timeout/)) {
79
+ return Promise.resolve({
80
+ message: "Response Timeout!!",
81
+ code: 504,
82
+ });
83
+ }
84
+ return Promise.resolve(error);
85
+ });
86
+ };
87
+
88
+ export default curl;
@@ -0,0 +1,2 @@
1
+ const utils = {};
2
+ export default utils;
@@ -0,0 +1,17 @@
1
+ <template>
2
+ <el-sub-menu :index="menuItem.key">
3
+ <template #title>{{ menuItem.name }} </template>
4
+ <div v-for="item in menuItem.subMenu" :key="item.key">
5
+ <SubMenu v-if="item.subMenu && item.subMenu.length > 0" :menuItem="item"></SubMenu>
6
+ <el-menu-item v-else :index="item.key">
7
+ {{ item.name }}
8
+ </el-menu-item>
9
+ </div>
10
+ </el-sub-menu>
11
+ </template>
12
+
13
+ <script setup>
14
+ const { menuItem } = defineProps(["menuItem"]);
15
+ </script>
16
+
17
+ <style lang="less" scoped></style>
@@ -0,0 +1,129 @@
1
+ <template>
2
+ <header-container :title="projName">
3
+ <template #menu-content>
4
+ <el-menu
5
+ :default-active="activeKey"
6
+ :ellipsis="false"
7
+ mode="horizontal"
8
+ @select="onMenuSelect"
9
+ >
10
+ <template v-for="item in menuStore.menuList">
11
+ <sub-menu
12
+ v-if="item.subMenu && item.subMenu.length > 0"
13
+ :menu-item="item"
14
+ :key="'sub-' + item.key"
15
+ ></sub-menu>
16
+ <el-menu-item v-else :key="'menu-' + item.key" :index="item.key">{{
17
+ item.name
18
+ }}</el-menu-item>
19
+ </template>
20
+ </el-menu>
21
+ </template>
22
+ <template #setting-content>
23
+ <!-- 根据projectStore.projectList渲染setting -->
24
+ <el-dropdown @command="handleProjectCommand">
25
+ <span class="projcet-list">
26
+ {{ projName }}
27
+ <el-icon
28
+ v-if="projectStore.projList.length > 1"
29
+ class="el-icon--right"
30
+ >
31
+ <ArrowDown />
32
+ </el-icon>
33
+ </span>
34
+ <template v-if="projectStore.projList.length > 1" #dropdown>
35
+ <el-dropdown-menu>
36
+ <el-dropdown-item
37
+ v-for="item in projectStore.projList"
38
+ :key="item.key"
39
+ :command="item.key"
40
+ :disabled="item.name === projName"
41
+ >
42
+ {{ item.name }}
43
+ </el-dropdown-item>
44
+ </el-dropdown-menu>
45
+ </template>
46
+ </el-dropdown>
47
+ </template>
48
+ <template #main-content>
49
+ <slot name="main-content"></slot>
50
+ </template>
51
+ </header-container>
52
+ </template>
53
+ <script setup>
54
+ import { ref, onMounted, watch } from "vue";
55
+ import { useRoute } from "vue-router";
56
+ import { ArrowDown } from "@element-plus/icons-vue";
57
+ import HeaderContainer from "$elpisWidgets/header-container/header-container.vue";
58
+ import SubMenu from "./complex-view/sub-menu/sub-menu.vue";
59
+ import { useProjectStore } from "$elpisStore/project.js";
60
+ import { useMenuStore } from "$elpisStore/menu.js";
61
+
62
+ const route = useRoute();
63
+ const menuStore = useMenuStore();
64
+ const projectStore = useProjectStore();
65
+
66
+ defineProps({
67
+ projName: {
68
+ type: String,
69
+ default: "项目列表",
70
+ },
71
+ });
72
+ const emit = defineEmits(["menu-select"]);
73
+ onMounted(() => {
74
+ setActiveKey();
75
+ });
76
+ const activeKey = ref("");
77
+ const setActiveKey = () => {
78
+ const menItem = menuStore.findMenuItem({
79
+ key: "key",
80
+ value: route.query.key,
81
+ });
82
+ activeKey.value = menItem?.key;
83
+ };
84
+ const onMenuSelect = (menuKey) => {
85
+ const menItem = menuStore.findMenuItem({
86
+ key: "key",
87
+ value: menuKey,
88
+ });
89
+ emit("menu-select", menItem);
90
+ };
91
+ const handleProjectCommand = (command) => {
92
+ const projItem = projectStore.projList.find((item) => item.key === command);
93
+ if (!projItem || !projItem.homePage) {
94
+ return;
95
+ }
96
+ const { host } = window.location;
97
+ window.location.replace(`http://${host}/view/dashboard${projItem.homePage}`);
98
+ };
99
+ watch(
100
+ () => route.query.key,
101
+ () => {
102
+ setActiveKey();
103
+ },
104
+ );
105
+ watch(
106
+ () => menuStore.menuList,
107
+ () => {
108
+ setActiveKey();
109
+ },
110
+ { deep: true },
111
+ );
112
+ </script>
113
+
114
+ <style lang="less" scoped>
115
+ .projcet-list {
116
+ margin-right: 20px;
117
+ cursor: pointer;
118
+ color: var(--el-color-primary);
119
+ display: flex;
120
+ align-items: center;
121
+ outline: none;
122
+ }
123
+ :deep(.el-menu) {
124
+ background-color: transparent;
125
+ }
126
+ :deep(.el-menu--horizontal.el-menu) {
127
+ border-bottom: 0;
128
+ }
129
+ </style>
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <iframe :src="path" class="iframe"></iframe>
3
+ </template>
4
+
5
+ <script setup>
6
+ import { ref, watch, onMounted } from "vue";
7
+ import { useRoute } from "vue-router";
8
+ import { useMenuStore } from "$elpisStore/menu.js";
9
+ const path = ref("");
10
+ const route = useRoute();
11
+ const menuStore = useMenuStore();
12
+ onMounted(() => {
13
+ setPath();
14
+ });
15
+ const setPath = () => {
16
+ const { key, sider_key: siderKey } = route.query;
17
+ const menuItem = menuStore.findMenuItem({
18
+ key: "key",
19
+ value: siderKey ?? key,
20
+ })
21
+ path.value = menuItem?.iframeConfig?.path ?? '';
22
+ console.log(path.value);
23
+ };
24
+ watch(
25
+ [
26
+ () => route.query.key,
27
+ () => route.query.sider_key,
28
+ () => menuStore.menuList,
29
+ ],
30
+ () => {
31
+ setPath();
32
+ },
33
+ { deep: true },
34
+ );
35
+ </script>
36
+
37
+ <style lang="less" scoped>
38
+ .iframe {
39
+ border: 0;
40
+ width: 100%;
41
+ height: 100%;
42
+ }
43
+ </style>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <el-card class="search-panel">
3
+ <schema-search-bar
4
+ :schema="searchSchema"
5
+ @load="onLoad"
6
+ @search="onSearch"
7
+ @reset="onReset"
8
+ ></schema-search-bar>
9
+ </el-card>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { inject } from "vue";
14
+ import SchemaSearchBar from "$elpisWidgets/schema-search-bar/schema-search-bar.vue";
15
+ const { searchSchema } = inject("schemaViewData");
16
+
17
+ const emit = defineEmits(["search"]);
18
+
19
+ const onLoad = (searchValObj) => {
20
+ emit("search", searchValObj);
21
+ }
22
+ const onSearch = (searchValObj) => {
23
+ emit("search", searchValObj);
24
+ }
25
+ const onReset = () => {
26
+ emit("search", {});
27
+ }
28
+ </script>
29
+
30
+ <style lang="less" scoped>
31
+ .search-panel {
32
+ margin: 10px;
33
+ }
34
+ :deep(.el-card__body) {
35
+ padding-bottom: 2px;
36
+ }
37
+ </style>
@@ -0,0 +1,114 @@
1
+ <template>
2
+ <el-card class="table-panel">
3
+ <!-- operation-panel -->
4
+ <el-row
5
+ v-if="tableConfig?.headerButtons?.length > 0"
6
+ justify="end"
7
+ class="operation-panel"
8
+ >
9
+ <el-button
10
+ v-for="item in tableConfig?.headerButtons"
11
+ v-bind="item"
12
+ @click="operationHandle({ btnConfig: item })"
13
+ >{{ item.label }}</el-button>
14
+ </el-row>
15
+ <!-- schema-table (组件 widget) -->
16
+ <schema-table
17
+ ref="schemaTableRef"
18
+ :schema="tableSchema"
19
+ :api="api"
20
+ :apiParams="apiParams"
21
+ :buttons="tableConfig?.rowButtons ?? []"
22
+ @operate="operationHandle"
23
+ ></schema-table>
24
+ </el-card>
25
+ </template>
26
+
27
+ <script setup>
28
+ import { ref, inject } from "vue";
29
+ import { ElMessageBox, ElNotification } from "element-plus";
30
+ import $curl from "$elpisCommon/curl.js";
31
+ import SchemaTable from "$elpisWidgets/schema-table/schema-table.vue";
32
+
33
+ const emit = defineEmits(["operate"]);
34
+ const { api, apiParams, tableSchema, tableConfig } = inject("schemaViewData");
35
+ const schemaTableRef = ref(null);
36
+ const EventHandleMap = {
37
+ remove: removeData,
38
+ };
39
+ const operationHandle = ({ btnConfig, rowData }) => {
40
+ const { eventKey } = btnConfig;
41
+ if (EventHandleMap[eventKey]) {
42
+ EventHandleMap[eventKey]({ btnConfig, rowData });
43
+ } else {
44
+ emit("operate", { btnConfig, rowData });
45
+ }
46
+ };
47
+ function removeData({ btnConfig, rowData }) {
48
+ const { eventOption } = btnConfig;
49
+ if (!eventOption?.params) return;
50
+ const { params } = eventOption;
51
+ const removeKey = Object.keys(params)[0];
52
+ let removeValue;
53
+ const removeValueList = params[removeKey].split("::");
54
+ if (removeValueList[0] === "schema" && removeValueList[1]) {
55
+ removeValue = rowData[removeValueList[1]];
56
+ }
57
+
58
+ ElMessageBox.confirm(
59
+ `确定要删除${removeKey}为:${removeValue}吗?`,
60
+ "Warning",
61
+ {
62
+ confirmButtonText: "确定",
63
+ cancelButtonText: "取消",
64
+ type: "warning",
65
+ },
66
+ ).then(async () => {
67
+ schemaTableRef.value.showLoading();
68
+ const res = await $curl({
69
+ method: "DELETE",
70
+ url: api.value,
71
+ data: {
72
+ [removeKey]: removeValue,
73
+ },
74
+ errorMessage: "删除失败",
75
+ });
76
+ schemaTableRef.value.hideLoading();
77
+ if (!res || !res.data || !res.success) {
78
+ return;
79
+ }
80
+ ElNotification({
81
+ message: "删除成功",
82
+ type: "success",
83
+ });
84
+ await initTableData();
85
+ });
86
+ }
87
+
88
+ const initTableData = async () => {
89
+ await schemaTableRef.value.initData();
90
+ };
91
+
92
+ const loadTableData = async () => {
93
+ await schemaTableRef.value.loadTableData();
94
+ };
95
+ defineExpose({
96
+ loadTableData,
97
+ });
98
+ </script>
99
+
100
+ <style lang="less" scoped>
101
+ .table-panel {
102
+ flex: 1;
103
+ margin: 10px;
104
+
105
+ .operation-panel {
106
+ margin-bottom: 10px;
107
+ }
108
+ }
109
+ :deep(.el-card__body) {
110
+ height: 98%;
111
+ display: flex;
112
+ flex-direction: column;
113
+ }
114
+ </style>
@@ -0,0 +1,22 @@
1
+ import createForm from "./create-form/create-form.vue";
2
+ import editForm from "./edit-form/edit-form.vue";
3
+ import detailPanel from "./detail-panel/detail-panel.vue";
4
+
5
+ // 业务扩展component 配置
6
+ import BusinessComponentConfig from "$businessSchemaViewConfig";
7
+
8
+ const ComponentConfig = {
9
+ createForm: {
10
+ component: createForm,
11
+ },
12
+ editForm: {
13
+ component: editForm,
14
+ },
15
+ detailPanel: {
16
+ component: detailPanel,
17
+ },
18
+ };
19
+ export default {
20
+ ...ComponentConfig,
21
+ ...BusinessComponentConfig,
22
+ };
@@ -0,0 +1,85 @@
1
+ <template>
2
+ <el-drawer
3
+ v-model="isShow"
4
+ direction="rtl"
5
+ :destroy-on-close="true"
6
+ :size="550"
7
+ >
8
+ <template #header>
9
+ <h3 class="title">{{ title }}</h3>
10
+ </template>
11
+ <template #default>
12
+ <schema-form
13
+ ref="schemaFormRef"
14
+ v-loading="loading"
15
+ :schema="components[name]?.schema"
16
+ ></schema-form>
17
+ </template>
18
+ <template #footer>
19
+ <el-button type="primary" @click="save">{{ saveBtnText }}</el-button>
20
+ </template>
21
+ </el-drawer>
22
+ </template>
23
+
24
+ <script setup>
25
+ import { ref, inject } from "vue";
26
+ import { ElNotification } from "element-plus";
27
+ import $curl from "$elpisCommon/curl";
28
+ import SchemaForm from "$elpisWidgets/schema-form/schema-form.vue";
29
+
30
+ const { api, components } = inject("schemaViewData");
31
+
32
+ const emit = defineEmits(["command"]);
33
+
34
+ const name = ref("createForm");
35
+
36
+ const loading = ref(false);
37
+ const schemaFormRef = ref(null);
38
+ const isShow = ref(false);
39
+ const title = ref("");
40
+ const saveBtnText = ref("");
41
+ const show = (rowData) => {
42
+ const { config } = components.value[name.value];
43
+ title.value = config?.title;
44
+ saveBtnText.value = config?.saveBtnText;
45
+ isShow.value = true;
46
+ };
47
+
48
+ const close = () => {
49
+ isShow.value = false;
50
+ }
51
+
52
+ const save = async () => {
53
+ if(loading.value) return;
54
+ if (!schemaFormRef.value.validate()) return;
55
+ loading.value = true;
56
+ const res = await $curl({
57
+ method: "POST",
58
+ url: api.value,
59
+ data: {
60
+ ...schemaFormRef.value.getValue(),
61
+ }
62
+ });
63
+ loading.value = false;
64
+ if(!res.success || !res) return;
65
+
66
+ ElNotification({
67
+ title: "创建成功",
68
+ message: "创建成功",
69
+ type: "success",
70
+ });
71
+
72
+ close();
73
+
74
+ emit("command", {
75
+ event: "loadTableData",
76
+ });
77
+ };
78
+
79
+ defineExpose({
80
+ name,
81
+ show,
82
+ });
83
+ </script>
84
+
85
+ <style lang="less" scoped></style>
@@ -0,0 +1,92 @@
1
+ <template>
2
+ <el-drawer
3
+ v-model="isShow"
4
+ direction="rtl"
5
+ :destroy-on-close="true"
6
+ :size="550"
7
+ >
8
+ <template #header>
9
+ <h3>{{ title }}</h3>
10
+ </template>
11
+ <template #default>
12
+ <el-card v-loading="loading" shadow="always" class="detail-panel">
13
+ <el-row
14
+ v-for="(item, key) in components[name]?.schema?.properties"
15
+ :key="key"
16
+ type="flex"
17
+ align="middle"
18
+ class="row-item"
19
+ >
20
+ <el-row class="item-label">{{ item.label }}:</el-row>
21
+ <el-row class="item-value">{{ dtoModel[key] }}</el-row>
22
+ </el-row>
23
+ </el-card>
24
+ </template>
25
+ </el-drawer>
26
+ </template>
27
+
28
+ <script setup>
29
+ import { ref, inject } from "vue";
30
+ import $curl from "$elpisCommon/curl";
31
+
32
+ const { api, components } = inject("schemaViewData");
33
+
34
+ const name = ref("detailPanel");
35
+ const loading = ref(false);
36
+ const isShow = ref(false);
37
+ const title = ref("");
38
+ const mainKey = ref("");
39
+ const mainValue = ref("");
40
+ const dtoModel = ref({});
41
+
42
+ const show = (rowData) => {
43
+ const { config } = components.value[name.value];
44
+
45
+ title.value = config.title;
46
+ mainKey.value = config.mainKey;
47
+ mainValue.value = rowData[config.mainKey];
48
+ dtoModel.value = {};
49
+ isShow.value = true;
50
+ fetchFormData();
51
+ };
52
+
53
+ const fetchFormData = async () => {
54
+ if (loading.value) return;
55
+ loading.value = true;
56
+ const res = await $curl({
57
+ method: "get",
58
+ url: api.value,
59
+ query: {
60
+ [mainKey.value]: mainValue.value,
61
+ },
62
+ });
63
+ loading.value = false;
64
+ if (!res || !res.data || !res.success) return;
65
+ dtoModel.value = res.data;
66
+ };
67
+
68
+ defineExpose({
69
+ name,
70
+ show,
71
+ });
72
+ </script>
73
+
74
+ <style lang="less" scoped>
75
+ .detail-panel {
76
+ border: 1px solid #a6a6a6;
77
+ padding: 30px;
78
+ .row-item {
79
+ height: 40px;
80
+ line-height: 40px;
81
+ font-size: 20px;
82
+ .item-label {
83
+ width: 120px;
84
+ margin-right: 20px;
85
+ color: #fff;
86
+ }
87
+ .item-value {
88
+ color: #d2dae4;
89
+ }
90
+ }
91
+ }
92
+ </style>