Commit afc65fd8bc5e24c544bddfd35e0adecd1f4ccffa

Authored by 黄 x
1 parent ae934227

feat(front): 前端增加组态中心页面

@@ -8,15 +8,15 @@ VITE_PUBLIC_PATH = / @@ -8,15 +8,15 @@ VITE_PUBLIC_PATH = /
8 # Please note that no line breaks 8 # Please note that no line breaks
9 9
10 # 本地 10 # 本地
11 -# VITE_PROXY = [["/api","http://192.168.10.113:8080/api"]] 11 +# VITE_PROXY = [["/api","http://localhost:8080/api"]]
12 12
13 # 线上演示环境 13 # 线上演示环境
14 # VITE_PROXY = [["/api","http://101.133.234.90:8080/api"]] 14 # VITE_PROXY = [["/api","http://101.133.234.90:8080/api"]]
15 # 线上测试环境 15 # 线上测试环境
16 -VITE_PROXY = [["/api","http://47.99.141.212:8080/api"]] 16 +VITE_PROXY = [["/api","http://localhost:8080/api"]]
17 17
18 # 实时数据的ws地址 18 # 实时数据的ws地址
19 -VITE_WEB_SOCKET = ws://47.99.141.212:8080/api/ws/plugins/telemetry?token= 19 +VITE_WEB_SOCKET = ws://localhost:8080/api/ws/plugins/telemetry?token=
20 20
21 # Delete console 21 # Delete console
22 VITE_DROP_CONSOLE = true 22 VITE_DROP_CONSOLE = true
@@ -29,3 +29,6 @@ VITE_GLOB_UPLOAD_URL=/api/yt/oss/upload @@ -29,3 +29,6 @@ VITE_GLOB_UPLOAD_URL=/api/yt/oss/upload
29 29
30 # Interface prefix 30 # Interface prefix
31 VITE_GLOB_API_URL_PREFIX=/yt 31 VITE_GLOB_API_URL_PREFIX=/yt
  32 +
  33 +#configuration
  34 +VITE_GLOB_CONFIGURATION = http://localhost:3000
@@ -16,12 +16,11 @@ VITE_BUILD_COMPRESS = 'gzip' @@ -16,12 +16,11 @@ VITE_BUILD_COMPRESS = 'gzip'
16 VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false 16 VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
17 17
18 # Basic interface address SPA 18 # Basic interface address SPA
19 -VITE_GLOB_API_URL=http://101.133.234.90:8080/api 19 +VITE_GLOB_API_URL=http://47.99.141.212:8080/api
20 20
21 # File upload address, optional 21 # File upload address, optional
22 # It can be forwarded by nginx or write the actual address directly 22 # It can be forwarded by nginx or write the actual address directly
23 -VITE_GLOB_UPLOAD_URL=http://101.133.234.90:8080/api/yt/oss/upload  
24 - 23 +VITE_GLOB_UPLOAD_URL=http://47.99.141.212:8080/api/yt/oss/upload
25 24
26 # Interface prefix 25 # Interface prefix
27 VITE_GLOB_API_URL_PREFIX=/yt 26 VITE_GLOB_API_URL_PREFIX=/yt
@@ -36,4 +35,7 @@ VITE_USE_PWA = false @@ -36,4 +35,7 @@ VITE_USE_PWA = false
36 VITE_LEGACY = true 35 VITE_LEGACY = true
37 36
38 # 实时数据的ws地址 37 # 实时数据的ws地址
39 -VITE_WEB_SOCKET = ws://101.133.234.90:8080/api/ws/plugins/telemetry?token= 38 +VITE_WEB_SOCKET = ws://47.99.141.212:8080/api/ws/plugins/telemetry?token=
  39 +
  40 +#configuration
  41 +VITE_GLOB_CONFIGURATION = http://localhost:3000
  1 +import { defHttp } from '/@/utils/http/axios';
  2 +import type {
  3 + queryPageParams,
  4 + ConfigurationModal,
  5 + ConfigurationCenterParams,
  6 + ConfigurationCenterInfo,
  7 +} from './model/configurationCenterModal';
  8 +import { getPageData } from '../../base';
  9 +enum API {
  10 + basicUrl = '/configuration/center',
  11 +}
  12 +
  13 +export const getPage = (params: queryPageParams) => {
  14 + return getPageData<ConfigurationModal>(params, API.basicUrl);
  15 +};
  16 +
  17 +export const saveConfigurationCenter = (params: ConfigurationCenterParams) => {
  18 + return defHttp.post({
  19 + url: API.basicUrl,
  20 + data: params,
  21 + });
  22 +};
  23 +
  24 +export const updateConfigurationCenter = (params: ConfigurationCenterParams) => {
  25 + return defHttp.put({
  26 + url: API.basicUrl,
  27 + data: params,
  28 + });
  29 +};
  30 +
  31 +export const deleteConfigurationCenter = (ids: string[]) => {
  32 + return defHttp.delete({
  33 + url: API.basicUrl,
  34 + data: {
  35 + ids: ids,
  36 + },
  37 + });
  38 +};
  39 +
  40 +export const saveOrUpdateConfigurationCenter = (
  41 + params: ConfigurationCenterInfo,
  42 + isUpdate: boolean
  43 +) => {
  44 + return isUpdate ? updateConfigurationCenter(params) : saveConfigurationCenter(params);
  45 +};
  1 +import { BasicPageParams } from '/@/api/model/baseModel';
  2 +import { ContactParams } from '/@/api/alarm/contact/model/alarmContactModal';
  3 +
  4 +interface ConfigurationCenterItemsModal {
  5 + id: string;
  6 + name: string;
  7 + createTime: string;
  8 + creator: string;
  9 + remark: string;
  10 +}
  11 +export type queryPageParams = BasicPageParams & { name: string; organizationId: string };
  12 +
  13 +export interface ConfigurationModal {
  14 + items: ConfigurationCenterItemsModal[];
  15 + total: number;
  16 +}
  17 +
  18 +export interface ConfigurationCenterParams {
  19 + name: string;
  20 + createTime: string;
  21 + creator: string;
  22 + remark: string;
  23 +}
  24 +export type ConfigurationCenterInfo = ConfigurationCenterParams;
@@ -28,6 +28,7 @@ export function getAppEnvConfig() { @@ -28,6 +28,7 @@ export function getAppEnvConfig() {
28 VITE_GLOB_APP_SHORT_NAME, 28 VITE_GLOB_APP_SHORT_NAME,
29 VITE_GLOB_API_URL_PREFIX, 29 VITE_GLOB_API_URL_PREFIX,
30 VITE_GLOB_UPLOAD_URL, 30 VITE_GLOB_UPLOAD_URL,
  31 + VITE_GLOB_CONFIGURATION,
31 } = ENV; 32 } = ENV;
32 33
33 if (!/^[a-zA-Z\_]*$/.test(VITE_GLOB_APP_SHORT_NAME)) { 34 if (!/^[a-zA-Z\_]*$/.test(VITE_GLOB_APP_SHORT_NAME)) {
@@ -42,6 +43,7 @@ export function getAppEnvConfig() { @@ -42,6 +43,7 @@ export function getAppEnvConfig() {
42 VITE_GLOB_APP_SHORT_NAME, 43 VITE_GLOB_APP_SHORT_NAME,
43 VITE_GLOB_API_URL_PREFIX, 44 VITE_GLOB_API_URL_PREFIX,
44 VITE_GLOB_UPLOAD_URL, 45 VITE_GLOB_UPLOAD_URL,
  46 + VITE_GLOB_CONFIGURATION,
45 }; 47 };
46 } 48 }
47 49
  1 +<template>
  2 + <BasicDrawer
  3 + v-bind="$attrs"
  4 + @register="registerDrawer"
  5 + showFooter
  6 + :title="getTitle"
  7 + width="30%"
  8 + @ok="handleSubmit"
  9 + >
  10 + <BasicForm @register="registerForm" />
  11 + </BasicDrawer>
  12 +</template>
  13 +<script lang="ts">
  14 + import { defineComponent, ref, computed, unref } from 'vue';
  15 + import { BasicForm, useForm } from '/@/components/Form';
  16 + import { formSchema } from './center.data';
  17 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  18 + import { useMessage } from '/@/hooks/web/useMessage';
  19 + import { saveOrUpdateConfigurationCenter } from '/@/api/configuration/center/configurationCenter';
  20 +
  21 + export default defineComponent({
  22 + name: 'ConfigurationDrawer',
  23 + components: { BasicDrawer, BasicForm },
  24 + emits: ['success', 'register'],
  25 + setup(_, { emit }) {
  26 + const isUpdate = ref(true);
  27 +
  28 + const [registerForm, { validate, setFieldsValue, resetFields }] = useForm({
  29 + labelWidth: 120,
  30 + schemas: formSchema,
  31 + showActionButtonGroup: false,
  32 + });
  33 +
  34 + const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
  35 + await resetFields();
  36 + setDrawerProps({ confirmLoading: false });
  37 + isUpdate.value = !!data?.isUpdate;
  38 + if (unref(isUpdate)) {
  39 + if (data.record.organizationDTO) {
  40 + await setFieldsValue(data.record);
  41 + } else {
  42 + Reflect.deleteProperty(data.record, 'organizationId');
  43 + await setFieldsValue(data.record);
  44 + }
  45 + }
  46 + });
  47 +
  48 + const getTitle = computed(() => (!unref(isUpdate) ? '新增组态中心' : '编辑组态中心'));
  49 +
  50 + async function handleSubmit() {
  51 + try {
  52 + const { createMessage } = useMessage();
  53 + const values = await validate();
  54 + setDrawerProps({ confirmLoading: true });
  55 + let saveMessage = '添加成功';
  56 + let updateMessage = '修改成功';
  57 + await saveOrUpdateConfigurationCenter(values, unref(isUpdate));
  58 + closeDrawer();
  59 + emit('success');
  60 + createMessage.success(unref(isUpdate) ? updateMessage : saveMessage);
  61 + } finally {
  62 + setDrawerProps({ confirmLoading: false });
  63 + }
  64 + }
  65 +
  66 + return {
  67 + getTitle,
  68 + registerDrawer,
  69 + registerForm,
  70 + handleSubmit,
  71 + };
  72 + },
  73 + });
  74 +</script>
  1 +import { BasicColumn, FormSchema } from '/@/components/Table';
  2 +import { getOrganizationList } from '/@/api/system/system';
  3 +import { copyTransFun } from '/@/utils/fnUtils';
  4 +
  5 +// 表格列数据
  6 +export const columns: BasicColumn[] = [
  7 + {
  8 + title: '组态名称',
  9 + dataIndex: 'name',
  10 + width: 120,
  11 + },
  12 + {
  13 + title: '所属组织',
  14 + dataIndex: 'organizationDTO.name',
  15 + width: 160,
  16 + },
  17 + {
  18 + title: '备注',
  19 + dataIndex: 'remark',
  20 + width: 200,
  21 + },
  22 + {
  23 + title: '创建时间',
  24 + dataIndex: 'createTime',
  25 + width: 120,
  26 + },
  27 + {
  28 + title: '更新时间',
  29 + dataIndex: 'updateTime',
  30 + width: 120,
  31 + },
  32 +];
  33 +
  34 +// 查询字段
  35 +export const searchFormSchema: FormSchema[] = [
  36 + {
  37 + field: 'name',
  38 + label: '组态名称',
  39 + component: 'Input',
  40 + colProps: { span: 8 },
  41 + componentProps: {
  42 + maxLength: 36,
  43 + placeholder: '请输入组态名称',
  44 + },
  45 + },
  46 +];
  47 +
  48 +export const formSchema: FormSchema[] = [
  49 + {
  50 + field: 'name',
  51 + label: '组态名称',
  52 + required: true,
  53 + component: 'Input',
  54 + componentProps: {
  55 + placeholder: '请输入组态名称',
  56 + maxLength: 255,
  57 + },
  58 + },
  59 + {
  60 + field: 'organizationId',
  61 + label: '所属组织',
  62 + required: true,
  63 + component: 'ApiTreeSelect',
  64 + componentProps: {
  65 + api: async () => {
  66 + const data = await getOrganizationList();
  67 + copyTransFun(data as any as any[]);
  68 + return data;
  69 + },
  70 + },
  71 + },
  72 + {
  73 + field: 'remark',
  74 + label: '备注',
  75 + component: 'InputTextArea',
  76 + componentProps: {
  77 + placeholder: '请输入备注',
  78 + maxLength: 255,
  79 + },
  80 + },
  81 + {
  82 + field: 'id',
  83 + label: '',
  84 + component: 'Input',
  85 + show: false,
  86 + componentProps: {
  87 + maxLength: 36,
  88 + placeholder: 'id',
  89 + },
  90 + },
  91 +];
  1 +<template>
  2 + <div>
  3 + <PageWrapper dense contentFullHeight contentClass="flex">
  4 + <OrganizationIdTree
  5 + class="w-1/4 xl:w-1/5"
  6 + @select="handleSelect"
  7 + ref="organizationIdTreeRef"
  8 + />
  9 + <BasicTable
  10 + :clickToRowSelect="false"
  11 + @register="registerTable"
  12 + :searchInfo="searchInfo"
  13 + class="w-3/4 xl:w-4/5"
  14 + >
  15 + <template #toolbar>
  16 + <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增组态中心 </a-button>
  17 + <a-button
  18 + type="primary"
  19 + color="error"
  20 + @click="handleDeleteOrBatchDelete(null)"
  21 + :disabled="hasBatchDelete"
  22 + >
  23 + 批量删除
  24 + </a-button>
  25 + </template>
  26 + <template #action="{ record }">
  27 + <TableAction
  28 + :actions="[
  29 + {
  30 + label: '设计',
  31 + icon: 'clarity:note-edit-line',
  32 + onClick: handleDesign.bind(null, record),
  33 + },
  34 + {
  35 + label: '预览',
  36 + icon: 'ant-design:eye-outlined',
  37 + onClick: handlePreview.bind(null, record),
  38 + },
  39 + {
  40 + label: '编辑',
  41 + icon: 'clarity:note-edit-line',
  42 + onClick: handleCreateOrEdit.bind(null, record),
  43 + },
  44 + {
  45 + label: '删除',
  46 + icon: 'ant-design:delete-outlined',
  47 + color: 'error',
  48 + popConfirm: {
  49 + title: '是否确认删除',
  50 + confirm: handleDeleteOrBatchDelete.bind(null, record),
  51 + },
  52 + },
  53 + ]"
  54 + />
  55 + </template>
  56 + </BasicTable>
  57 + </PageWrapper>
  58 + <ContactDrawer @register="registerDrawer" @success="handleSuccess" />
  59 + </div>
  60 +</template>
  61 +
  62 +<script lang="ts">
  63 + import { defineComponent, reactive, ref, computed } from 'vue';
  64 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  65 + import { PageWrapper } from '/@/components/Page';
  66 + import { useMessage } from '/@/hooks/web/useMessage';
  67 + import { useDrawer } from '/@/components/Drawer';
  68 + import ContactDrawer from './ConfigurationCenterDrawer.vue';
  69 + import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree';
  70 + import { searchFormSchema, columns } from './center.data';
  71 + import {
  72 + getPage,
  73 + deleteConfigurationCenter,
  74 + } from '/@/api/configuration/center/configurationCenter';
  75 + import { getAppEnvConfig } from '/@/utils/env';
  76 + export default defineComponent({
  77 + components: {
  78 + PageWrapper,
  79 + OrganizationIdTree,
  80 + BasicTable,
  81 + TableAction,
  82 + ContactDrawer,
  83 + },
  84 + setup() {
  85 + const { VITE_GLOB_CONFIGURATION } = getAppEnvConfig();
  86 + let selectedRowIds = ref<string[]>([]);
  87 + const hasBatchDelete = computed(() => selectedRowIds.value.length <= 0);
  88 + // 复选框事件
  89 + const onSelectRowChange = (selectedRowKeys: string[]) => {
  90 + selectedRowIds.value = selectedRowKeys;
  91 + };
  92 + const searchInfo = reactive<Recordable>({});
  93 + const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
  94 + // 表格hooks
  95 + const [registerTable, { reload }] = useTable({
  96 + title: '组态中心列表',
  97 + api: getPage,
  98 + columns,
  99 + clickToRowSelect: false,
  100 + formConfig: {
  101 + labelWidth: 120,
  102 + schemas: searchFormSchema,
  103 + resetFunc: resetFn,
  104 + },
  105 + showIndexColumn: false,
  106 + useSearchForm: true,
  107 + showTableSetting: true,
  108 + bordered: true,
  109 + rowSelection: {
  110 + onChange: onSelectRowChange,
  111 + type: 'checkbox',
  112 + },
  113 + rowKey: 'id',
  114 + actionColumn: {
  115 + width: 200,
  116 + title: '操作',
  117 + dataIndex: 'action',
  118 + slots: { customRender: 'action' },
  119 + fixed: 'right',
  120 + },
  121 + });
  122 + // 弹框
  123 + const [registerDrawer, { openDrawer }] = useDrawer();
  124 + const { createMessage } = useMessage();
  125 +
  126 + // 刷新
  127 + const handleSuccess = () => {
  128 + reload();
  129 + };
  130 + // 新增或编辑
  131 + const handleCreateOrEdit = (record: Recordable | null) => {
  132 + if (record) {
  133 + openDrawer(true, {
  134 + isUpdate: true,
  135 + record,
  136 + });
  137 + } else {
  138 + openDrawer(true, {
  139 + isUpdate: false,
  140 + });
  141 + }
  142 + };
  143 + // 删除或批量删除
  144 + const handleDeleteOrBatchDelete = async (record: Recordable | null) => {
  145 + if (record) {
  146 + try {
  147 + await deleteConfigurationCenter([record.id]);
  148 + createMessage.success('删除组态成功');
  149 + handleSuccess();
  150 + } catch (e) {}
  151 + } else {
  152 + try {
  153 + await deleteConfigurationCenter(selectedRowIds.value);
  154 + createMessage.success('批量删除组态成功');
  155 + selectedRowIds.value = [];
  156 + handleSuccess();
  157 + } catch (e) {}
  158 + }
  159 + };
  160 +
  161 + // 树形选择器
  162 + const handleSelect = (organizationId: string) => {
  163 + searchInfo.organizationId = organizationId;
  164 + handleSuccess();
  165 + };
  166 +
  167 + const handlePreview = (record: Recordable | null) => {
  168 + window.open(VITE_GLOB_CONFIGURATION + '/?dev=1', '_blank');
  169 + };
  170 + const handleDesign = (record: Recordable | null) => {
  171 + window.open(VITE_GLOB_CONFIGURATION + '/?dev=1&project=2', '_blank');
  172 + };
  173 + return {
  174 + searchInfo,
  175 + hasBatchDelete,
  176 + handleCreateOrEdit,
  177 + handleDeleteOrBatchDelete,
  178 + handleSelect,
  179 + handleSuccess,
  180 + handlePreview,
  181 + handleDesign,
  182 + registerTable,
  183 + registerDrawer,
  184 + organizationIdTreeRef,
  185 + };
  186 + },
  187 + });
  188 +</script>
@@ -158,4 +158,6 @@ export interface GlobEnvConfig { @@ -158,4 +158,6 @@ export interface GlobEnvConfig {
158 VITE_GLOB_APP_SHORT_NAME: string; 158 VITE_GLOB_APP_SHORT_NAME: string;
159 // Upload url 159 // Upload url
160 VITE_GLOB_UPLOAD_URL?: string; 160 VITE_GLOB_UPLOAD_URL?: string;
  161 + //configuration
  162 + VITE_GLOB_CONFIGURATION: string;
161 } 163 }