diff --git a/public/images/network/01.jpg b/public/images/network/01.jpg deleted file mode 100644 index 950b64d7..00000000 Binary files a/public/images/network/01.jpg and /dev/null differ diff --git a/public/images/network/01.png b/public/images/network/01.png new file mode 100644 index 00000000..9ec5cdc8 Binary files /dev/null and b/public/images/network/01.png differ diff --git a/public/images/network/02.jpg b/public/images/network/02.jpg index 745ccacc..950b64d7 100644 Binary files a/public/images/network/02.jpg and b/public/images/network/02.jpg differ diff --git a/public/images/network/03.png b/public/images/network/03.png new file mode 100644 index 00000000..a9e8e8d3 Binary files /dev/null and b/public/images/network/03.png differ diff --git a/public/images/network/03.jpg b/public/images/network/04.jpg similarity index 100% rename from public/images/network/03.jpg rename to public/images/network/04.jpg diff --git a/public/images/network/05.jpg b/public/images/network/05.jpg new file mode 100644 index 00000000..e15d4962 Binary files /dev/null and b/public/images/network/05.jpg differ diff --git a/public/images/network/06.jpg b/public/images/network/06.jpg new file mode 100644 index 00000000..e5a2f45a Binary files /dev/null and b/public/images/network/06.jpg differ diff --git a/src/api/device/category.ts b/src/api/device/category.ts new file mode 100644 index 00000000..d18e3587 --- /dev/null +++ b/src/api/device/category.ts @@ -0,0 +1,25 @@ +// 产品分类 +import server from '@/utils/request' +import { CategoryItem } from '@/views/device/Category/typings' +/** + * 查询产品分类树形数据 + */ + +export const queryTree = (params?: Record) => server.post('/device/category/_tree', params) + +/** + * 保存树形数据 + */ + export const saveTree = (data: any) =>server.post('/device/category', data) + + + /** + * 根据Id修改 + */ + export const updateTree = (data: any, id:string) => server.put(`/device/category/${id}`, data) + + /** + * 根据Id删除数据 + */ + + export const deleteTree = (id:string) => server.remove(`/device/category/${id}`) \ No newline at end of file diff --git a/src/api/device/instance.ts b/src/api/device/instance.ts index 9f051caf..19df86c2 100644 --- a/src/api/device/instance.ts +++ b/src/api/device/instance.ts @@ -1,6 +1,7 @@ +import { LocalStore } from '@/utils/comm' import server from '@/utils/request' -import { BASE_API_PATH } from '@/utils/variable' -import { DeviceInstance } from '@/views/device/instance/typings' +import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable' +import { DeviceInstance } from '@/views/device/Instance/typings' /** * 删除设备物模型 @@ -97,5 +98,5 @@ export const batchDeleteDevice = (data: string[]) => server.put(`/device-instanc * @param type 文件类型 * @returns */ - export const deviceExport = (productId: string, type: string) => `${BASE_API_PATH}/device-instance${!!productId ? '/' + productId : ''}/export.${type}` +export const deviceExport = (productId: string, type: string) => `${BASE_API_PATH}/device-instance${!!productId ? '/' + productId : ''}/export.${type}` diff --git a/src/api/device/product.ts b/src/api/device/product.ts index 6f318dcf..11c70020 100644 --- a/src/api/device/product.ts +++ b/src/api/device/product.ts @@ -42,4 +42,11 @@ export const detail = (id: string) => server.get(`/device-product/$ * 产品分类 * @param data */ -export const category = (data: any) => server.post('/device/category/_tree', data) \ No newline at end of file +export const category = (data: any) => server.post('/device/category/_tree', data) + +/** + * 保存产品 + * @param data 产品信息 + * @returns + */ +export const saveProductMetadata = (data: Record) => server.patch('/device-product', data) \ No newline at end of file diff --git a/src/api/home.js b/src/api/home.js deleted file mode 100644 index ea3aa339..00000000 --- a/src/api/home.js +++ /dev/null @@ -1,8 +0,0 @@ -import server from '@/utils/request'; - -// 设备数量 -export const getDeviceCount_api = () => server.get(`/device/instance/_count`); -// 产品数量 -export const getProductCount_api = (data) => server.post(`/device-product/_count`, data); -// 查询产品列表 -export const getProductList_api = (data) => server.get(`/device/product/_query/no-paging?paging=false`, data); diff --git a/src/api/home.ts b/src/api/home.ts new file mode 100644 index 00000000..a37c0f3d --- /dev/null +++ b/src/api/home.ts @@ -0,0 +1,17 @@ +import server from '@/utils/request'; + +// 当前登录用户权限信息 +export const getMe_api = () => server.get(`/authorize/me`); +// 设置登录用户选择的页面 +export const setView_api = (data:object) => server.patch(`/user/settings/view/user`, data); +// 当前登录用户选择的页面 +export const getView_api = () => server.get(`/user/settings/view/user`); + +// 设备数量 +export const getDeviceCount_api = () => server.get(`/device/instance/_count`); +// 产品数量 +export const getProductCount_api = (data:object) => server.post(`/device-product/_count`, data); +// 查询产品列表 +export const getProductList_api = (data:object={}) => server.get(`/device/product/_query/no-paging?paging=false`, data); +// 查询设备列表 +export const getDeviceList_api = (data:object) => server.post(`/device-instance/_query/`, data); diff --git a/src/api/iot-card/cardManagement.ts b/src/api/iot-card/cardManagement.ts new file mode 100644 index 00000000..390685e0 --- /dev/null +++ b/src/api/iot-card/cardManagement.ts @@ -0,0 +1,67 @@ +import server from '@/utils/request' + +/** + * 不分页查询平台对接 + * @param data + */ +export const queryPlatformNoPage = (data: any) => server.post(`/network/card/platform/_query/no-paging`, data) + +/** + * 分页查询物联卡管理列表 + * @param data + */ +export const query = (data: any) => server.post(`/network/card/_query`, data) + +/** + * 激活待激活物联卡 + * @param cardId + */ +export const changeDeploy = (cardId: string) => server.get(`/network/card/${cardId}/_activation`); + +/** + * 停用已激活物联卡 + * @param cardId + */ +export const unDeploy = (cardId: string) => server.get(`/network/card/${cardId}/_deactivate`); + +/** + * 复机已停机物联卡 + * @param cardId + */ +export const resumption = (cardId: string) => server.get(`/network/card/${cardId}/_resumption`); + +/** + * 删除物联卡 + * @param id + */ +export const del = (id: string) => server.remove(`/network/card/${id}`); + + +/** + * 激活待激活物联卡(批量) + * @param data + */ +export const changeDeployBatch = (data: any) => server.get(`/network/card/_activation/_bitch`, data); + +/** + * 停用已激活物联卡(批量) + * @param data + */ +export const unDeployBatch = (data: any) => server.get(`/network/card/_deactivate/_bitch`, data); + +/** + * 复机已停机物联卡(批量) + * @param data + */ +export const resumptionBatch = (data: any) => server.get(`/network/card/_resumption/_bitch`, data); + +/** + * 同步物联卡状态 + */ +export const sync = () => server.get(`/network/card/state/_sync`); + +/** + * 批量删除物联卡 + * @param data + */ +export const removeCards = (data: any) => server.post(`/network/card/batch/_delete`, data); \ No newline at end of file diff --git a/src/api/login.js b/src/api/login.js deleted file mode 100644 index 461d7628..00000000 --- a/src/api/login.js +++ /dev/null @@ -1,17 +0,0 @@ -import server from '@/utils/request' - -export const config = () => server.get(`/authorize/captcha/config`) - -export const code = () => server.get(`/authorize/captcha/image?width=130&height=30`) - -export const authLogin = (data) => server.post(`/authorize/login`, data) - -export const getInitSet = () => server.get(`/user/settings/init`) - -export const postInitSet = (data) => server.post(`/user/settings/init`, data) - -export const systemVersion = () => server.get(`/system/version`) - -export const bindInfo = () => server.get(`/application/sso/_all`) - -export const settingDetail = (scopes) => server.get(`/system/config/${scopes}`) \ No newline at end of file diff --git a/src/api/login.ts b/src/api/login.ts new file mode 100644 index 00000000..33684901 --- /dev/null +++ b/src/api/login.ts @@ -0,0 +1,49 @@ +import server from '@/utils/request' + +/** + * 获取验证码配置 + * @returns + */ +export const config = () => server.get(`/authorize/captcha/config`) + +/** + * 获取验证码图片 + * @returns + */ +export const code = () => server.get(`/authorize/captcha/image?width=130&height=30`) + +/** + * 登录 + * @returns + */ +export const authLogin = (data: any) => server.post(`/authorize/login`, data) + +/** + * 查询初始化配置信息 + * @returns + */ +export const getInitSet = () => server.get(`/user/settings/init`) + +/** + * 创建初始化配置信息 + * @returns + */ +export const postInitSet = (data: any) => server.post(`/user/settings/init`, data) + +/** + * 查询系统版本信息 + * @returns + */ +export const systemVersion = () => server.get(`/system/version`) + +/** + * 获取支持的SSO的应用 + * @returns + */ +export const bindInfo = () => server.get(`/application/sso/_all`) + +/** + * 查询配置信息 + * @returns + */ +export const settingDetail = (scopes: string) => server.get(`/system/config/${scopes}`) \ No newline at end of file diff --git a/src/api/notice/config.ts b/src/api/notice/config.ts index 9ed55cf8..ccdebc7c 100644 --- a/src/api/notice/config.ts +++ b/src/api/notice/config.ts @@ -1,4 +1,5 @@ -import { patch, post, get } from '@/utils/request' +import { patch, post, get, remove } from '@/utils/request' +import { TemplateFormData } from '@/views/notice/Template/types' export default { // 列表 @@ -8,5 +9,30 @@ export default { // 新增 save: (data: any) => post(`/notifier/config`, data), // 修改 - update: (data: any) => patch(`/notifier/config`, data) + update: (data: any) => patch(`/notifier/config`, data), + del: (id: string) => remove(`/notifier/config/${id}`), + getTemplate: (data: any, id: string) => post(`/notifier/template/${id}/_query`, data), + getTemplateDetail: (id: string) => get(`/notifier/template/${id}/detail`), + debug: (data: any, configId: string, templateId: string) => post(`/notifier/${configId}/${templateId}/_send`, data), + getHistory: (data: any, id: string) => post(`/notify/history/config/${id}/_query`, data), + // 获取所有平台用户 + getPlatformUsers: () => post(`/user/_query/no-paging`, { paging: false }), + // 钉钉部门 + dingTalkDept: (id: string) => get(`/notifier/dingtalk/corp/${id}/departments/tree`), + // 钉钉部门人员 + getDingTalkUsers: (configId: string, deptId: string) => get(`/notifier/dingtalk/corp/${configId}/${deptId}/users`), + // 钉钉已经绑定的人员 + getDingTalkBindUsers: (id: string) => get(`/user/third-party/dingTalk_dingTalkMessage/${id}`), + // 钉钉绑定用户 + dingTalkBindUser: (data: any, id: string) => patch(`/user/third-party/dingTalk_dingTalkMessage/${id}`, data), + // 微信部门 + weChatDept: (id: string) => get(`/notifier/wechat/corp/${id}/departments`), + // 微信部门人员 + getWeChatUsers: (configId: string, deptId: string) => get(`/notifier/wechat/corp/${configId}/${deptId}/users`), + // 微信已经绑定的人员 + getWeChatBindUsers: (id: string) => get(`/user/third-party/weixin_corpMessage/${id}`), + // 微信绑定用户 + weChatBindUser: (data: any, id: string) => patch(`/user/third-party/weixin_corpMessage/${id}`, data), + // 解绑 + unBindUser: (data: any, id: string) => post(`/user/third-party/${id}/_unbind`, data) } \ No newline at end of file diff --git a/src/api/notice/template.ts b/src/api/notice/template.ts index b49dbd8b..45c90010 100644 --- a/src/api/notice/template.ts +++ b/src/api/notice/template.ts @@ -1,4 +1,5 @@ -import { patch, post, get } from '@/utils/request' +import { patch, post, get, remove } from '@/utils/request' +import { BindConfig } from '@/views/notice/Template/types' export default { // 列表 @@ -8,5 +9,19 @@ export default { // 新增 save: (data: any) => post(`/notifier/template`, data), // 修改 - update: (data: any) => patch(`/notifier/template`, data) + update: (data: any) => patch(`/notifier/template`, data), + del: (id: any) => remove(`/notifier/template/${id}`), + getConfig: (data: any) => post(`/notifier/config/_query/no-paging?paging=false`, data), + getTemplateDetail: (id: string) => get(`/notifier/template/${id}/detail`), + debug: (data: any, configId: string, templateId: string) => post(`/notifier/${configId}/${templateId}/_send`, data), + getHistory: (data: any, id: string) => post(`/notify/history/template/${id}/_query`, data), + // 钉钉/微信, 根据配置获取部门和用户 + getDept: (type: string, id: string) => get(`/notifier/${type}/corp/${id}/departments`), + getUser: (type: string, id: string) => get(`/notifier/${type}/corp/${id}/users`), + // 微信获取标签推送 + getTags: (id: string) => get(`/notifier/wechat/corp/${id}/tags`), + // 语音/短信获取阿里云模板 + getAliTemplate: (id: any) => get(`/notifier/sms/aliyun/${id}/templates`), + // 短信获取签名 + getSigns: (id: any) => get(`/notifier/sms/aliyun/${id}/signs`) } \ No newline at end of file diff --git a/src/api/system/permission.ts b/src/api/system/permission.ts new file mode 100644 index 00000000..659abbed --- /dev/null +++ b/src/api/system/permission.ts @@ -0,0 +1,15 @@ +import server from '@/utils/request'; + +// 获取权限列表 +export const getPermission_api = (data: object) => server.post(`/permission/_query/`, data); +// 新增时校验标识id是否可用 +export const checkId_api = (data: object) => server.get(`/permission/id/_validate`, data); +// 修改权限 | 导入文件内容 +export const editPermission_api = (data: object) => server.patch(`/permission`, data); +// 添加权限 +export const addPermission_api = (data: object) => server.post(`/permission`, data); +// 删除权限 +export const delPermission_api = (id: string) => server.remove(`/permission/${id}`); + +// 导出权限数据 +export const exportPermission_api = (data: object) => server.post(`/permission/_query/no-paging`, data); diff --git a/src/components/AIcon/index.tsx b/src/components/AIcon/index.tsx index dddebb75..58efea27 100644 --- a/src/components/AIcon/index.tsx +++ b/src/components/AIcon/index.tsx @@ -27,7 +27,18 @@ const iconKeys = [ 'SyncOutlined', 'ExclamationCircleOutlined', 'UploadOutlined', - 'LoadingOutlined' + 'LoadingOutlined', + 'PlusCircleOutlined', + 'QuestionCircleOutlined', + 'DisconnectOutlined', + 'LinkOutlined', + 'PoweroffOutlined', + 'SwapOutlined', + 'BugOutlined', + 'BarsOutlined', + 'ArrowDownOutlined', + 'SmallDashOutlined', + 'TeamOutlined', ] const Icon = (props: {type: string}) => { diff --git a/src/components/RadioCard/index.vue b/src/components/RadioCard/index.vue index 2d27ba0b..152ae840 100644 --- a/src/components/RadioCard/index.vue +++ b/src/components/RadioCard/index.vue @@ -25,6 +25,7 @@ interface IOption { type Emits = { (e: 'update:modelValue', data: string): void; + (e: 'change') :void }; const emit = defineEmits(); @@ -41,7 +42,10 @@ const props = defineProps({ const myValue = computed({ get: () => props.modelValue, - set: (val) => emit('update:modelValue', val), + set: (val) => { + emit('update:modelValue', val) + emit('change') + }, }); diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx index 92069199..7c43d1f7 100644 --- a/src/components/Table/index.tsx +++ b/src/components/Table/index.tsx @@ -54,7 +54,7 @@ export interface JTableProps extends TableProps{ rowSelection?: TableProps['rowSelection']; cardProps?: Record; dataSource?: Record[]; - gridColumn: number; + gridColumn?: number; /** * 用于不同分辨率 * gridColumns[0] 1366 ~ 1440 分辨率; diff --git a/src/components/ValueItem/index.vue b/src/components/ValueItem/index.vue index 7a01b89e..3e7528ae 100644 --- a/src/components/ValueItem/index.vue +++ b/src/components/ValueItem/index.vue @@ -109,7 +109,7 @@ const props = defineProps({ // 组件类型 itemType: { type: String, - default: () => 'geoPoint', + default: () => 'string', }, // 下拉选择框下拉数据 options: { diff --git a/src/router/menu.ts b/src/router/menu.ts index 27d4f961..2e92daff 100644 --- a/src/router/menu.ts +++ b/src/router/menu.ts @@ -109,6 +109,10 @@ export default [ path:'/system/Role/detail/:id', component: ()=>import('@/views/system/Role/Detail/index.vue') }, + { + path:'/system/Permission', + component: ()=>import('@/views/system/Permission/index.vue') + }, // 初始化 { path: '/init-home', @@ -116,9 +120,17 @@ export default [ }, // 物联卡 iot-card { - path: '/iot-card/home', + path: '/iot-card/Home', component: () => import('@/views/iot-card/Home/index.vue') }, + { + path: '/iot-card/Dashboard', + component: () => import('@/views/iot-card/Dashboard/index.vue') + }, + { + path: '/iot-card/CardManagement', + component: () => import('@/views/iot-card/CardManagement/index.vue') + }, // 北向输出 { path: '/northbound/DuerOS', @@ -128,4 +140,10 @@ export default [ path: '/northbound/AliCloud', component: () => import('@/views/northbound/AliCloud/index.vue') }, + + // 产品分类 + { + path: '/iot/device/Category', + component: () => import('@/views/device/Category/index.vue') + } ] \ No newline at end of file diff --git a/src/store/instance.ts b/src/store/instance.ts index f4d6e145..eb51df72 100644 --- a/src/store/instance.ts +++ b/src/store/instance.ts @@ -1,4 +1,4 @@ -import { DeviceInstance, InstanceModel } from "@/views/device/instance/typings"; +import { DeviceInstance, InstanceModel } from "@/views/device/Instance/typings" import { defineStore } from "pinia"; export const useInstanceStore = defineStore({ @@ -7,6 +7,7 @@ export const useInstanceStore = defineStore({ actions: { setCurrent(current: Partial) { this.current = current + this.detail = current } } }) \ No newline at end of file diff --git a/src/store/metadata.ts b/src/store/metadata.ts new file mode 100644 index 00000000..c793f233 --- /dev/null +++ b/src/store/metadata.ts @@ -0,0 +1,31 @@ +import { DeviceInstance, InstanceModel } from "@/views/device/Instance/typings" +import { defineStore } from "pinia"; +import type { MetadataItem, MetadataType } from '@/views/device/Product/typings' + +type MetadataModelType = { + item: MetadataItem | unknown; + edit: boolean; + type: MetadataType; + action: 'edit' | 'add'; + import: boolean; + importMetadata: boolean; +}; + +export const useMetadataStore = defineStore({ + id: 'metadata', + state: () => ({ + model: { + item: undefined, + edit: false, + type: 'events', + action: 'add', + import: false, + importMetadata: false, + } as MetadataModelType + }), + actions: { + set(key: string, value: any) { + this.model[key] = value + } + } +}) \ No newline at end of file diff --git a/src/utils/comm.ts b/src/utils/comm.ts index a2bb3385..3c032a79 100644 --- a/src/utils/comm.ts +++ b/src/utils/comm.ts @@ -6,7 +6,7 @@ import { Terms } from 'components/Search/types' * @param path {String} 路径 */ export const getImage = (path: string) => { - return new URL('/images'+path, import.meta.url).href + return new URL('/images' + path, import.meta.url).href } export const LocalStore = { @@ -57,3 +57,30 @@ export const filterTreeSelectNode = (value: string, treeNode: any, key: string = export const filterSelectNode = (value: string, option: any, key: string = 'label'): boolean => { return option[key]?.includes(value) } + +/** + * 时间转换为'2022-01-02 14:03:05' + * @param date 时间对象 + * @returns + */ +export const dateFormat = (dateSouce:any):string|Error => { + let date = null + try { + date = new Date(dateSouce) + } catch (error) { + return new Error('请传入日期格式数据') + } + let year = date.getFullYear(); + let month: number | string = date.getMonth() + 1; + let day: number | string = date.getDate(); + let hour: number | string = date.getHours(); + let minutes: number | string = date.getMinutes(); + let seconds: number | string = date.getSeconds(); + month = (month < 10) ? '0' + month : month; + day = (day < 10) ? '0' + day : day; + hour = (hour < 10) ? '0' + hour : hour; + minutes = (minutes < 10) ? '0' + minutes : minutes; + seconds = (seconds < 10) ? '0' + seconds : seconds; + return year + "-" + month + "-" + day + + " " + hour + ":" + minutes + ":" + seconds; +} diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 3e5df69b..239ee90f 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,6 +1,7 @@ import moment from "moment"; import { LocalStore } from "./comm"; import { TOKEN_KEY } from "./variable"; +import {SystemConst} from './consts'; /** * 把数据下载成JSON @@ -52,4 +53,23 @@ export const downloadObject = (record: Record, fileName: string, fo document.body.appendChild(formElement); formElement.submit(); document.body.removeChild(formElement); -}; \ No newline at end of file +}; +// 是否不是community版本 +export const isNoCommunity = !(localStorage.getItem(SystemConst.VERSION_CODE) === 'community'); + + +/** + * 生成随机数 + * @param length + * @returns + */ +export const randomString = (length?: number) => { + const tempLength = length || 32; + const chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; + const maxPos = chars.length; + let pwd = ''; + for (let i = 0; i < tempLength; i += 1) { + pwd += chars.charAt(Math.floor(Math.random() * maxPos)); + } + return pwd; +}; diff --git a/src/views/device/Category/components/modifyModal/index.vue b/src/views/device/Category/components/modifyModal/index.vue new file mode 100644 index 00000000..ea420fa9 --- /dev/null +++ b/src/views/device/Category/components/modifyModal/index.vue @@ -0,0 +1,203 @@ + + + + diff --git a/src/views/device/Category/index.vue b/src/views/device/Category/index.vue new file mode 100644 index 00000000..f97ba614 --- /dev/null +++ b/src/views/device/Category/index.vue @@ -0,0 +1,221 @@ + + + + diff --git a/src/views/device/Category/typings.d.ts b/src/views/device/Category/typings.d.ts new file mode 100644 index 00000000..36656078 --- /dev/null +++ b/src/views/device/Category/typings.d.ts @@ -0,0 +1,10 @@ +export type CategoryItem = { + id: string; + name: string; + level: number; + key: string; + parentId: string; + path: string; + sortIndex: number; + children?: Category[]; +}; diff --git a/src/views/device/components/Metadata/Base/Edit/index.vue b/src/views/device/components/Metadata/Base/Edit/index.vue new file mode 100644 index 00000000..1f0f0de7 --- /dev/null +++ b/src/views/device/components/Metadata/Base/Edit/index.vue @@ -0,0 +1,119 @@ + + + \ No newline at end of file diff --git a/src/views/device/components/Metadata/Base/columns.ts b/src/views/device/components/Metadata/Base/columns.ts new file mode 100644 index 00000000..7c4f0f63 --- /dev/null +++ b/src/views/device/components/Metadata/Base/columns.ts @@ -0,0 +1,91 @@ +import { JColumnProps } from "@/components/Table"; + +const SourceMap = { + device: '设备', + manual: '手动', + rule: '规则', +}; + +const type = { + read: '读', + write: '写', + report: '上报', +}; + +const BaseColumns: JColumnProps[] = [ + { + title: '标识', + dataIndex: 'id', + ellipsis: true, + }, + { + title: '名称', + dataIndex: 'name', + ellipsis: true, + }, + { + title: '说明', + dataIndex: 'description', + ellipsis: true, + }, +]; + +const EventColumns: JColumnProps[] = BaseColumns.concat([ + { + title: '事件级别', + dataIndex: 'expands', + scopedSlots: true, + }, +]); + +const FunctionColumns: JColumnProps[] = BaseColumns.concat([ + { + title: '是否异步', + dataIndex: 'async', + scopedSlots: true, + }, + // { + // title: '读写类型', + // dataIndex: 'expands', + // render: (text: any) => (text?.type || []).map((item: string | number) => {type[item]}), + // }, +]); + +const PropertyColumns: JColumnProps[] = BaseColumns.concat([ + { + title: '数据类型', + dataIndex: 'valueType', + scopedSlots: true, + }, + { + title: '属性来源', + dataIndex: 'expands', + scopedSlots: true, + }, + { + title: '读写类型', + dataIndex: 'expands', + scopedSlots: true, + }, +]); + +const TagColumns: JColumnProps[] = BaseColumns.concat([ + { + title: '数据类型', + dataIndex: 'valueType', + scopedSlots: true, + }, + { + title: '读写类型', + dataIndex: 'expands', + scopedSlots: true, + }, +]); + +const MetadataMapping = new Map(); +MetadataMapping.set('properties', PropertyColumns); +MetadataMapping.set('events', EventColumns); +MetadataMapping.set('tags', TagColumns); +MetadataMapping.set('functions', FunctionColumns); + +export default MetadataMapping; \ No newline at end of file diff --git a/src/views/device/components/Metadata/Base/index.vue b/src/views/device/components/Metadata/Base/index.vue new file mode 100644 index 00000000..35e9dfed --- /dev/null +++ b/src/views/device/components/Metadata/Base/index.vue @@ -0,0 +1,100 @@ + + + \ No newline at end of file diff --git a/src/views/device/components/Metadata/Import/index.vue b/src/views/device/components/Metadata/Import/index.vue index eda57092..fb6028bd 100644 --- a/src/views/device/components/Metadata/Import/index.vue +++ b/src/views/device/components/Metadata/Import/index.vue @@ -47,14 +47,16 @@ import { saveMetadata } from '@/api/device/instance' import { queryNoPagingPost, convertMetadata, modify } from '@/api/device/product' import type { DefaultOptionType } from 'ant-design-vue/es/select'; import { UploadProps } from 'ant-design-vue/es'; -import type { DeviceMetadata } from '@/views/device/Product/typings' +import type { DeviceMetadata, ProductItem } from '@/views/device/Product/typings' import { message } from 'ant-design-vue/es'; import { Store } from 'jetlinks-store'; import { SystemConst } from '@/utils/consts'; import { useInstanceStore } from '@/store/instance' +import { useProductStore } from '@/store/product'; const route = useRoute() const instanceStore = useInstanceStore() +const productStore = useProductStore() interface Props { visible: boolean, @@ -191,8 +193,10 @@ const handleImport = async () => { const { id } = route.params || {} if (props?.type === 'device') { await saveMetadata(id as string, metadata) + instanceStore.setCurrent(JSON.parse(metadata || '{}')) } else { await modify(id as string, { metadata: metadata }) + productStore.setCurrent(JSON.parse(metadata || '{}')) } loading.value = false // MetadataAction.insert(JSON.parse(metadata || '{}')); @@ -231,10 +235,12 @@ const handleImport = async () => { if (props?.type === 'device') { const metadata: DeviceMetadata = JSON.parse(paramsDevice || '{}') // MetadataAction.insert(metadata); + instanceStore.setCurrent(metadata) message.success('导入成功') } else { - const metadata: DeviceMetadata = JSON.parse(params?.metadata || '{}') + const metadata: ProductItem = JSON.parse(params?.metadata || '{}') // MetadataAction.insert(metadata); + productStore.setCurrent(metadata) message.success('导入成功') } } diff --git a/src/views/device/components/Metadata/metadata.ts b/src/views/device/components/Metadata/metadata.ts new file mode 100644 index 00000000..134a67c0 --- /dev/null +++ b/src/views/device/components/Metadata/metadata.ts @@ -0,0 +1,61 @@ +import { saveProductMetadata } from "@/api/device/product"; +import { saveMetadata } from "@/api/device/instance"; +import type { DeviceInstance } from "../../Instance/typings"; +import type { DeviceMetadata, MetadataItem, MetadataType, ProductItem } from "../../Product/typings"; + +/** + * 更新物模型 + * @param type 物模型类型 events + * @param item 物模型数据 【{a},{b},{c}】 + // * @param target product、device + * @param data product 、device [{event:[1,2,3]] + * @param onEvent 数据更新回调:更新数据库、发送事件等操作 + * + */ + export const updateMetadata = ( + type: MetadataType, + item: MetadataItem[], + // target: 'product' | 'device', + data: ProductItem | DeviceInstance, + onEvent?: (item: string) => void, +): ProductItem | DeviceInstance => { + if (!data) return data; + const metadata = JSON.parse(data.metadata || '{}') as DeviceMetadata; + const config = (metadata[type] || []) as MetadataItem[]; + if (item.length > 0) { + item.forEach((i) => { + const index = config.findIndex((c) => c.id === i.id); + if (index > -1) { + config[index] = i; + // onEvent?.('update', i); + } else { + config.push(i); + // onEvent?.('add', i); + } + }); + } else { + console.warn('未触发物模型修改'); + } + // @ts-ignore + metadata[type] = config.sort((a, b) => b?.sortsIndex - a?.sortsIndex); + data.metadata = JSON.stringify(metadata); + onEvent?.(data.metadata) + return data; +}; + +/** + * 保存物模型数据到服务器 + * @param type 类型 + * @param data 数据 + */ +export const asyncUpdateMetadata = ( + type: 'product' | 'device', + data: ProductItem | DeviceInstance, +): Promise => { + switch (type) { + case 'product': + return saveProductMetadata(data); + case 'device': + return saveMetadata(data.id, JSON.parse(data.metadata || '{}')); + } +}; \ No newline at end of file diff --git a/src/views/home/components/InitHome/index.vue b/src/views/home/components/InitHome/index.vue index 57be6d23..888aae8a 100644 --- a/src/views/home/components/InitHome/index.vue +++ b/src/views/home/components/InitHome/index.vue @@ -7,37 +7,47 @@ - 确定 + 确定 diff --git a/src/views/home/components/StepCard.vue b/src/views/home/components/StepCard.vue index ccc87a5d..661de226 100644 --- a/src/views/home/components/StepCard.vue +++ b/src/views/home/components/StepCard.vue @@ -21,11 +21,11 @@
- - @@ -38,8 +38,8 @@ import { PropType } from 'vue'; import { QuestionCircleOutlined } from '@ant-design/icons-vue'; import { message } from 'ant-design-vue'; -import AccessMethodDialog from './dialogs/AccessMethodDialog.vue'; -import FuncTestDialog from './dialogs/FuncTestDialog.vue'; +import ProductChooseDialog from './dialogs/ProductChooseDialog.vue'; +import DeviceChooseDialog from './dialogs/DeviceChooseDialog.vue'; import { recommendList } from '../index'; @@ -73,9 +73,8 @@ const jumpPage = (row: recommendList) => { } }; // 弹窗返回后的二次跳转 -const againJumpPage = (paramsSource: object) => { - const params = { ...(selectRow.params || {}), ...paramsSource }; - router.push(`${selectRow.linkUrl}${objToParams(params || {})}`); +const againJumpPage = (params: string) => { + router.push(`${selectRow.linkUrl}/${params}`); }; const objToParams = (source: object): string => { diff --git a/src/views/home/components/dialogs/DeviceChooseDialog.vue b/src/views/home/components/dialogs/DeviceChooseDialog.vue new file mode 100644 index 00000000..18a03947 --- /dev/null +++ b/src/views/home/components/dialogs/DeviceChooseDialog.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/src/views/home/components/dialogs/FuncTestDialog.vue b/src/views/home/components/dialogs/FuncTestDialog.vue deleted file mode 100644 index f04db868..00000000 --- a/src/views/home/components/dialogs/FuncTestDialog.vue +++ /dev/null @@ -1,98 +0,0 @@ - - - - - diff --git a/src/views/home/components/dialogs/AccessMethodDialog.vue b/src/views/home/components/dialogs/ProductChooseDialog.vue similarity index 96% rename from src/views/home/components/dialogs/AccessMethodDialog.vue rename to src/views/home/components/dialogs/ProductChooseDialog.vue index 6bf83d48..07cb6e95 100644 --- a/src/views/home/components/dialogs/AccessMethodDialog.vue +++ b/src/views/home/components/dialogs/ProductChooseDialog.vue @@ -53,7 +53,7 @@ const productList = ref<[productItem] | []>([]); const getContainer = () => proxy?.$refs.modal as HTMLElement; const getOptions = () => { - getProductList_api().then((resp) => { + getProductList_api().then((resp:any) => { productList.value = resp.result .filter((i: any) => !i?.accessId) .map((item: { name: any; id: any }) => ({ @@ -63,7 +63,7 @@ const getOptions = () => { }); }; const handleOk = () => { - emits('confirm', form.value); + emits('confirm', form.value.productId); visible.value = false; }; const filterOption = (input: string, option: any) => { diff --git a/src/views/home/index.d.ts b/src/views/home/index.d.ts index 6b8a22bb..19b3c366 100644 --- a/src/views/home/index.d.ts +++ b/src/views/home/index.d.ts @@ -8,7 +8,11 @@ export interface recommendList { auth: boolean; dialogTag?: 'accessMethod' | 'funcTest'; } - +// 产品列表里的每项 +export interface productItem { + label: string; + value: string +} export interface deviceInfo { deviceId: string, deviceName: string, diff --git a/src/views/home/index.vue b/src/views/home/index.vue index 7129a745..1327a1eb 100644 --- a/src/views/home/index.vue +++ b/src/views/home/index.vue @@ -2,11 +2,11 @@
-
- - - - +
+ + + +
@@ -17,6 +17,39 @@ import DeviceHome from './components/DeviceHome/index.vue'; import DevOpsHome from './components/DevOpsHome/index.vue'; import ComprehensiveHome from './components/ComprehensiveHome/index.vue'; +import { isNoCommunity } from '@/utils/utils'; +import { getMe_api, getView_api } from '@/api/home'; + +const router = useRouter(); + +const currentView = ref(''); +const loading = ref(true); + +// 获取选择的视图 +const setCurrentView = () => { + getView_api().then((resp: any) => { + if (resp.status === 200) { + if (resp.result) currentView.value = resp.result?.content; + else if (resp.result.username === 'admin') { + currentView.value = 'comprehensive'; + } else currentView.value = 'init'; + } + }); +}; + +if (isNoCommunity) { + // 判断是否是api用户 是则跳转 否则获取选中的视图 + getMe_api().then((resp: any) => { + if (resp && resp.status === 200) { + const isApiUser = resp.result.dimensions.find( + (item: any) => + item.type === 'api-client' || item.type.id === 'api-client', + ); + + isApiUser ? router.push('/system/api') : setCurrentView(); + } + }); +}else setCurrentView() diff --git a/src/views/iot-card/Dashboard/index.vue b/src/views/iot-card/Dashboard/index.vue new file mode 100644 index 00000000..93bc1cfa --- /dev/null +++ b/src/views/iot-card/Dashboard/index.vue @@ -0,0 +1,323 @@ + + + + + diff --git a/src/views/iot-card/components/LineChart.vue b/src/views/iot-card/components/LineChart.vue new file mode 100644 index 00000000..9d22543b --- /dev/null +++ b/src/views/iot-card/components/LineChart.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/src/views/link/AccessConfig/Detail/index.vue b/src/views/link/AccessConfig/Detail/index.vue index e8c820a4..f84b13fb 100644 --- a/src/views/link/AccessConfig/Detail/index.vue +++ b/src/views/link/AccessConfig/Detail/index.vue @@ -16,6 +16,12 @@ /> + +
@@ -28,6 +34,8 @@ import Provider from '../components/Provider/index.vue'; import { getProviders, detail } from '@/api/link/accessConfig'; import Media from '../components/Media/index.vue'; import Channel from '../components/Channel/index.vue'; +import Edge from '../components/Edge/index.vue'; +import Cloud from '../components/Cloud/index.vue'; // const router = useRouter(); const route = useRoute(); diff --git a/src/views/link/AccessConfig/components/Channel/index.vue b/src/views/link/AccessConfig/components/Channel/index.vue index 658c940d..15b30253 100644 --- a/src/views/link/AccessConfig/components/Channel/index.vue +++ b/src/views/link/AccessConfig/components/Channel/index.vue @@ -82,10 +82,11 @@
- + + diff --git a/src/views/link/AccessConfig/components/Cloud/OneNet.vue b/src/views/link/AccessConfig/components/Cloud/OneNet.vue new file mode 100644 index 00000000..79f91f71 --- /dev/null +++ b/src/views/link/AccessConfig/components/Cloud/OneNet.vue @@ -0,0 +1,736 @@ + + + + + diff --git a/src/views/link/AccessConfig/components/Cloud/index.vue b/src/views/link/AccessConfig/components/Cloud/index.vue new file mode 100644 index 00000000..dfa6dc39 --- /dev/null +++ b/src/views/link/AccessConfig/components/Cloud/index.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/src/views/link/AccessConfig/components/Edge/index.vue b/src/views/link/AccessConfig/components/Edge/index.vue new file mode 100644 index 00000000..6798e357 --- /dev/null +++ b/src/views/link/AccessConfig/components/Edge/index.vue @@ -0,0 +1,492 @@ + + + + + diff --git a/src/views/link/AccessConfig/components/Media/GB28181.vue b/src/views/link/AccessConfig/components/Media/GB28181.vue index 239486ec..77540348 100644 --- a/src/views/link/AccessConfig/components/Media/GB28181.vue +++ b/src/views/link/AccessConfig/components/Media/GB28181.vue @@ -6,7 +6,7 @@
- + 配置设备信令参数
@@ -511,7 +511,12 @@ import { message, Form } from 'ant-design-vue'; import type { FormInstance } from 'ant-design-vue'; import { getResourcesCurrent, getClusters } from '@/api/link/accessConfig'; -import { DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue'; +import { + DeleteOutlined, + PlusOutlined, + QuestionCircleOutlined, + InfoCircleOutlined, +} from '@ant-design/icons-vue'; import { update, save } from '@/api/link/accessConfig'; interface Form2 { diff --git a/src/views/link/AccessConfig/components/Network.vue b/src/views/link/AccessConfig/components/Network.vue index edd2c5c1..04bebf34 100644 --- a/src/views/link/AccessConfig/components/Network.vue +++ b/src/views/link/AccessConfig/components/Network.vue @@ -6,7 +6,7 @@
- + 选择与设备通信的网络组件
- + 使用选择的消息协议,对网络组件通信数据进行编解码、认证等操作
{ - if (info.file.status === 'done') { - const result = info.file.response?.result; - console.log('result: ', result); - } -}; +// const fileList = computed({ +// get: () => props.attachments.map((m) => ({ id: fileId(), ...m })), +// set: (val) => +// emit( +// 'update:attachments', +// val.map(({ name, location }) => ({ name, location })), +// ), +// }); const fileList = ref([]); + watch( () => props.attachments, (val) => { - fileList.value = val; + fileList.value = val.map((m) => ({ + id: fileId(), + ...m, + })); }, { deep: true }, ); -const handleDelete = (id: number) => { - const idx = fileList.value.findIndex((f) => f.id === id); - fileList.value.splice(idx, 1); - emit('update:attachments', fileList.value); +const handleChange = (info: UploadChangeParam, id: string | undefined) => { + if (info.file.status === 'done') { + const targetFileIdx = fileList.value.findIndex((f) => f.id === id); + fileList.value[targetFileIdx].name = info.file.name; + fileList.value[targetFileIdx].location = info.file.response?.result; + emit( + 'update:attachments', + fileList.value.map(({ name, location }) => ({ name, location })), + ); + } }; + +/** + * 删除附件 + * @param id + */ +const handleDelete = (id: string | undefined) => { + const idx = fileList.value.findIndex((f) => f.id === id); + + fileList.value.splice(idx, 1); +}; + +/** + * 添加附件 + */ const handleAdd = () => { fileList.value.push({ - id: fileList.value.length, + id: fileId(), name: '', location: '', }); - emit('update:attachments', fileList.value); }; + +/** + * 附件标识 + */ +const fileId = () => String(new Date().getTime() + Math.random() * 9); diff --git a/src/views/notice/Template/Detail/components/ToTag.vue b/src/views/notice/Template/Detail/components/ToTag.vue new file mode 100644 index 00000000..28f469b7 --- /dev/null +++ b/src/views/notice/Template/Detail/components/ToTag.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/src/views/notice/Template/Detail/components/ToUser.vue b/src/views/notice/Template/Detail/components/ToUser.vue new file mode 100644 index 00000000..21bd9aa2 --- /dev/null +++ b/src/views/notice/Template/Detail/components/ToUser.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/src/views/notice/Template/Detail/components/VariableDefinitions.vue b/src/views/notice/Template/Detail/components/VariableDefinitions.vue new file mode 100644 index 00000000..f167289c --- /dev/null +++ b/src/views/notice/Template/Detail/components/VariableDefinitions.vue @@ -0,0 +1,136 @@ + + + + + + diff --git a/src/views/notice/Template/Detail/index.vue b/src/views/notice/Template/Detail/index.vue index b281c75b..82ce27eb 100644 --- a/src/views/notice/Template/Detail/index.vue +++ b/src/views/notice/Template/Detail/index.vue @@ -39,6 +39,7 @@ - {{ item.label }} + {{ item.name }} @@ -120,8 +122,7 @@ > @@ -179,58 +180,33 @@ - - - {{ item.label }} - - + :type="formData.type" + :config-id="formData.configId" + /> - - - {{ item.label }} - - + :type="formData.type" + :config-id="formData.configId" + /> - - - {{ item.label }} - - + @@ -246,17 +222,11 @@ - - {{ item.label }} - - + /> - {{ item.label }} + {{ item.templateName }} @@ -383,10 +353,18 @@ label="签名" v-bind="validateInfos['template.signName']" > - + placeholder="请选择签名" + > + + {{ item.signName }} + + @@ -418,6 +396,35 @@
+ + + + + + { - console.log('formData.value.type: ', formData.value.type); + // console.log('formData.value.type: ', formData.value.type); Object.assign( formData.value.template, TEMPLATE_FIELD_MAP[formData.value.type][formData.value.provider], @@ -547,11 +560,42 @@ const { resetFields, validate, validateInfos, clearValidate } = useForm( watch( () => formData.value.type, () => { + formData.value.variableDefinitions = []; clearValidate(); }, { deep: true }, ); +watch( + () => formData.value.template.message, + (val) => { + if (!val) return; + // 已经存在的变量 + const oldKey = formData.value.variableDefinitions?.map((m) => m.id); + // 正则提取${}里面的值 + const pattern = /(?<=\$\{).*?(?=\})/g; + const titleList = val.match(pattern)?.filter((f) => f); + const newKey = [...new Set(titleList)]; + const result = newKey?.map((m) => + oldKey.includes(m) + ? formData.value.variableDefinitions.find( + (item) => item.id === m, + ) + : { + id: m, + name: '', + type: 'string', + format: '%s', + }, + ); + formData.value.variableDefinitions = result as IVariableDefinitions[]; + }, + { deep: true }, +); + +/** + * 获取详情 + */ const getDetail = async () => { const res = await templateApi.detail(route.params.id as string); // console.log('res: ', res); @@ -560,6 +604,50 @@ const getDetail = async () => { }; // getDetail(); +/** + * 获取绑定配置 + */ +const configList = ref(); +const getConfigList = async () => { + const terms = [ + { column: 'type$IN', value: formData.value.type }, + { column: 'provider', value: formData.value.provider }, + ]; + const { result } = await templateApi.getConfig({ terms }); + configList.value = result; +}; +getConfigList(); + +/** + * 配置选择改变 + */ +const handleConfigChange = () => { + getTemplateList(); + getSignsList(); +}; + +/** + * 获取阿里模板 + */ +const templateList = ref(); +const getTemplateList = async () => { + const { result } = await templateApi.getAliTemplate( + formData.value.configId, + ); + templateList.value = result; +}; +getTemplateList(); + +/** + * 获取签名 + */ +const signsList = ref(); +const getSignsList = async () => { + const { result } = await templateApi.getSigns(formData.value.configId); + signsList.value = result; +}; +getSignsList(); + /** * 表单提交 */ @@ -567,25 +655,37 @@ const btnLoading = ref(false); const handleSubmit = () => { validate() .then(async () => { - console.log('formData.value: ', formData.value); + // console.log('formData.value: ', formData.value); + formData.value.template.ttsCode = + formData.value.template.templateCode; btnLoading.value = true; - // let res; - // if (!formData.value.id) { - // res = await templateApi.save(formData.value); - // } else { - // res = await templateApi.update(formData.value); - // } - // // console.log('res: ', res); - // if (res?.success) { - // message.success('保存成功'); - // router.back(); - // } - btnLoading.value = false; + let res; + if (!formData.value.id) { + res = await templateApi.save(formData.value); + } else { + res = await templateApi.update(formData.value); + } + // console.log('res: ', res); + if (res?.success) { + message.success('保存成功'); + router.back(); + } }) .catch((err) => { console.log('err: ', err); + btnLoading.value = false; }); }; + +// test +watch( + () => formData.value, + (val) => { + console.log('formData.value: ', val); + }, + { deep: true }, +); +// test diff --git a/src/views/notice/Template/index.vue b/src/views/notice/Template/index.vue index 3201947b..5f2313fd 100644 --- a/src/views/notice/Template/index.vue +++ b/src/views/notice/Template/index.vue @@ -1,22 +1,399 @@ - - +/** + * 根据通知方式展示对应logo + */ +const getLogo = (type: string, provider: string) => { + return MSG_TYPE[type].find((f: any) => f.value === provider)?.logo; +}; +/** + * 通知方式字段展示对应文字 + */ +const getMethodTxt = (type: string) => { + return NOTICE_METHOD.find((f) => f.value === type)?.label; +}; + +/** + * 新增 + */ +const handleAdd = () => { + router.push(`/notice/Config/detail/:id`); +}; + +/** + * 导入 + */ +const beforeUpload = (file: any) => { + console.log('file: ', file); + const reader = new FileReader(); + reader.readAsText(file); + reader.onload = async (result) => { + const text = result.target?.result; + console.log('text: ', text); + if (!file.type.includes('json')) { + message.error('请上传json格式文件'); + return false; + } + try { + const data = JSON.parse(text || '{}'); + const { success } = await ConfigApi.update(data); + if (success) { + message.success('操作成功'); + configRef.value.reload(); + } + return true; + } catch { + // message.error('请上传json格式文件'); + } + return true; + }; + return false; +}; + +/** + * 导出 + */ +const handleExport = () => { + downloadObject(configRef.value.dataSource, `通知配置`); +}; + +/** + * 查看 + */ +const handleView = (id: string) => { + message.warn(id + '暂未开发'); +}; + +const syncVis = ref(false); +const debugVis = ref(false); +const logVis = ref(false); +const currentConfig = ref>>(); +const getActions = ( + data: Partial>, + type: 'card' | 'table', +): ActionsType[] => { + if (!data) return []; + const actions = [ + { + key: 'edit', + text: '编辑', + tooltip: { + title: '编辑', + }, + icon: 'EditOutlined', + onClick: () => { + // visible.value = true; + // current.value = data; + router.push(`/notice/Config/detail/${data.id}`); + }, + }, + { + key: 'debug', + text: '调试', + tooltip: { + title: '调试', + }, + icon: 'BugOutlined', + onClick: () => { + debugVis.value = true; + currentConfig.value = data; + }, + }, + { + key: 'debug', + text: '通知记录', + tooltip: { + title: '通知记录', + }, + icon: 'BarsOutlined', + onClick: () => { + logVis.value = true; + currentConfig.value = data; + }, + }, + { + key: 'debug', + text: '导出', + tooltip: { + title: '导出', + }, + icon: 'ArrowDownOutlined', + onClick: () => { + downloadObject(data, `通知配置`); + }, + }, + { + key: 'delete', + text: '删除', + popConfirm: { + title: '确认删除?', + onConfirm: async () => { + const resp = await ConfigApi.del(data.id); + if (resp.status === 200) { + message.success('操作成功!'); + configRef.value?.reload(); + } else { + message.error('操作失败!'); + } + }, + }, + icon: 'DeleteOutlined', + }, + ]; + return actions; +}; + + diff --git a/src/views/notice/Template/types.d.ts b/src/views/notice/Template/types.d.ts index 54bea847..54aad7ff 100644 --- a/src/views/notice/Template/types.d.ts +++ b/src/views/notice/Template/types.d.ts @@ -7,13 +7,25 @@ export interface IHeaders { interface IAttachments { location: string; name: string; - id?: number; + id?: string; } interface IVariableDefinitions { id: string; name: string; type: string; format: string; + value?: string; +} + +interface IMarkDown { + text: string; + title: string; +} +interface ILink { + title: string; + picUrl: string; + messageUrl: string; + text: string; } export type TemplateFormData = { @@ -23,16 +35,8 @@ export type TemplateFormData = { message?: string; // 钉钉机器人 messageType?: string; - markdown?: { - text: string; - title: string; - }; - link?: { - title: string; - picUrl: string; - messageUrl: string; - text: string; - }; + markdown?: IMarkDown; + link?: ILink; // 微信 // agentId?: string; // message?: string; @@ -71,4 +75,24 @@ export type TemplateFormData = { creatorId?: string; createTime?: number; configId?: string; -}; \ No newline at end of file +}; + +// 绑定配置类型 +export type config = { + host: string; + password: string; + port: number; + sender: string; + ssl: boolean; + username: string; +} +export type BindConfig = { + configuration: config; + createTime: number + creatorId: string; + id: string; + maxRetryTimes: number; + name: string; + provider: string; + type: string +} \ No newline at end of file diff --git a/src/views/system/Permission/components/EditDialog.vue b/src/views/system/Permission/components/EditDialog.vue new file mode 100644 index 00000000..953a084d --- /dev/null +++ b/src/views/system/Permission/components/EditDialog.vue @@ -0,0 +1,321 @@ + + + + + diff --git a/src/views/system/Permission/components/StatusLabel.vue b/src/views/system/Permission/components/StatusLabel.vue new file mode 100644 index 00000000..7641fea2 --- /dev/null +++ b/src/views/system/Permission/components/StatusLabel.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/src/views/system/Permission/index.vue b/src/views/system/Permission/index.vue new file mode 100644 index 00000000..d221cc98 --- /dev/null +++ b/src/views/system/Permission/index.vue @@ -0,0 +1,298 @@ + + + + + diff --git a/src/views/system/Role/Detail/index.vue b/src/views/system/Role/Detail/index.vue index 1c58b369..8a907baa 100644 --- a/src/views/system/Role/Detail/index.vue +++ b/src/views/system/Role/Detail/index.vue @@ -1,6 +1,5 @@ @@ -59,8 +59,8 @@ import { import AddDialog from './components/AddDialog.vue'; import { getRoleList_api, delRole_api } from '@/api/system/role'; import { message } from 'ant-design-vue'; - -const router = useRouter() +const addDialogRef = ref(); // 新增弹窗实例 +const router = useRouter(); // 筛选 const query = reactive({ columns: [ @@ -122,24 +122,21 @@ const table = reactive({ ], tableData: [], clickAdd: () => { - dialog.openAdd += 1; + addDialogRef.value.openDialog(true, {}) }, clickDel: (row: any) => { - delRole_api(row.id).then((resp:any)=>{ - if(resp.status === 200){ - tableRef.value?.reload() - message.success('操作成功!') + delRole_api(row.id).then((resp: any) => { + if (resp.status === 200) { + tableRef.value?.reload(); + message.success('操作成功!'); } - }) + }); }, clickEdit: (row: any) => { - router.push(`/system/Role/detail/${row.id}`) + router.push(`/system/Role/detail/${row.id}`); }, }); -// 弹窗相关 -const dialog = reactive({ - openAdd: 0, -}); + diff --git a/src/views/user/Login/index.vue b/src/views/user/Login/index.vue index d41703b3..c5248629 100644 --- a/src/views/user/Login/index.vue +++ b/src/views/user/Login/index.vue @@ -83,19 +83,20 @@ ]" > - + > + + 记住密码记住我 @@ -180,7 +188,6 @@ import { bindInfo, settingDetail, } from '@/api/login'; -import Cookies from 'js-cookie'; import { useUserInfo } from '@/store/userInfo'; import { LocalStore } from '@/utils/comm'; import { BASE_API_PATH, TOKEN_KEY, Version_Code } from '@/utils/variable'; @@ -220,34 +227,24 @@ iconMap.set('dingtalk-ent-app', getImage('/bind/dingtalk.png')); iconMap.set('wechat-webapp', getImage('/bind/wechat-webapp.png')); const onFinish = async () => { - form.remember - ? Cookies.set('user', encodeURIComponent(JSON.stringify(form)), { - expires: 7, - }) - : Cookies.remove('user'); - Cookies.set('username', form.username, { expires: 30 }); try { loading.value = true; const res: any = await authLogin(form); + loading.value = false; if (res.success) { store.$patch({ ...res.result, username: form.username, }); LocalStore.set(TOKEN_KEY, res?.result.token); - // if (res.result.username === 'admin') { - // const resp: any = await getInitSet(); - // if (resp.status === 200 && !resp.result.length) { - // window.location.href = '/#/init-home'; - // return; - // } - // } - // window.location.href = '/'; - - const resp: any = await getInitSet(); - if (resp.success) { - router.push('/demo'); + if (res.result.username === 'admin') { + const resp: any = await getInitSet(); + if (resp.status === 200 && !resp.result.length) { + window.location.href = '/#/init-home'; + return; + } } + window.location.href = '/'; } } catch (error) { form.verifyCode = ''; @@ -269,14 +266,6 @@ const getCode = async () => { } }; -const getCookie = () => { - // form.username = Cookies.get('username'); - if (!Cookies.get('user')) return; - const user = JSON.parse(decodeURIComponent(Cookies.get('user'))); - form.username = user.username; - form.password = user.password; - form.remember = user.remember || false; -}; const getOpen = () => { LocalStore.removeAll(); @@ -292,7 +281,7 @@ const getOpen = () => { } } }); - settingDetail('front').then((res) => { + settingDetail('front').then((res: any) => { if (res.status === 200) { const ico: any = document.querySelector('link[rel="icon"]'); ico.href = res.result.ico; @@ -337,7 +326,6 @@ watch( getOpen(); getCode(); -getCookie(); screenRotation(screenWidth.value, screenHeight.value); @@ -470,23 +458,9 @@ screenRotation(screenWidth.value, screenHeight.value); } .verifyCode { - .login-code-input { - width: 70%; - float: left; - } - .login-code { - width: 30%; - height: 32px; - float: left; - background-color: #e4e6e7; - img { - cursor: pointer; - vertical-align: middle; - } - .login-code-img { - width: 100%; - height: 100%; - } + img { + cursor: pointer; + // vertical-align: middle; } } }