Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	components.d.ts
This commit is contained in:
xieyonghong 2023-01-11 16:12:01 +08:00
commit 3cfee37765
44 changed files with 3018 additions and 515 deletions

1
.gitignore vendored
View File

@ -11,7 +11,6 @@ node_modules
dist
dist-ssr
*.local
yarn.lock
components.d.ts
# Editor directories and files

6
components.d.ts vendored
View File

@ -7,22 +7,27 @@ export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
ABadge: typeof import('ant-design-vue/es')['Badge']
AButton: typeof import('ant-design-vue/es')['Button']
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
ACol: typeof import('ant-design-vue/es')['Col']
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
ADivider: typeof import('ant-design-vue/es')['Divider']
AEmpty: typeof import('ant-design-vue/es')['Empty']
AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem']
AInput: typeof import('ant-design-vue/es')['Input']
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
APagination: typeof import('ant-design-vue/es')['Pagination']
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
ARow: typeof import('ant-design-vue/es')['Row']
ASelect: typeof import('ant-design-vue/es')['Select']
ASpace: typeof import('ant-design-vue/es')['Space']
ASpin: typeof import('ant-design-vue/es')['Spin']
ASwitch: typeof import('ant-design-vue/es')['Switch']
ATable: typeof import('ant-design-vue/es')['Table']
ATimePicker: typeof import('ant-design-vue/es')['TimePicker']
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
ATreeSelect: typeof import('ant-design-vue/es')['TreeSelect']
@ -35,6 +40,7 @@ declare module '@vue/runtime-core' {
PermissionButton: typeof import('./src/components/PermissionButton/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Table: typeof import('./src/components/Table/index.vue')['default']
TitleComponent: typeof import('./src/components/TitleComponent/index.vue')['default']
ValueItem: typeof import('./src/components/ValueItem/index.vue')['default']
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 B

3
src/api/device.ts Normal file
View File

@ -0,0 +1,3 @@
import server from '@/utils/request'
export const deleteMetadata = (deviceId: string) => server.remove(`/device-instance/${deviceId}/metadata`)

8
src/api/home.js Normal file
View File

@ -0,0 +1,8 @@
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);

View File

@ -0,0 +1,3 @@
import server from '@/utils/request'
export const save = (data) => server.post(`/network/certificate`, data)

View File

@ -0,0 +1,6 @@
import server from '@/utils/request';
// 获取tree数据-第一层
export const getTreeOne_api = () => server.get(`/v3/api-docs/swagger-config`);
// 获取tree数据-第二层
export const getTreeTwo_api = (name:string) => server.get(`/v3/api-docs/${name}`);

View File

@ -60,7 +60,7 @@
</div>
<!-- 按钮 -->
<slot name="botton-tool">
<slot name="bottom-tool">
<div v-if="showTool" class="card-tools">
<div
v-for="item in actions"

View File

@ -0,0 +1,273 @@
<template>
<a-spin :spinning="loading">
<div class="jtable-body">
<div class="jtable-body-header">
<div class="jtable-body-header-left">
<slot name="headerTitle"></slot>
</div>
<div class="jtable-body-header-right" v-if="!model">
<div class="jtable-setting-item" :class="[ModelEnum.CARD === _model ? 'active' : '']" @click="modelChange(ModelEnum.CARD)">
<AppstoreOutlined />
</div>
<div class="jtable-setting-item" :class="[ModelEnum.TABLE === _model ? 'active' : '']" @click="modelChange(ModelEnum.TABLE)">
<UnorderedListOutlined />
</div>
</div>
</div>
<div class="jtable-content">
<!-- <div class="jtable-alert">
<a-alert message="Info Text" type="info" />
</div> -->
<div v-if="_model === ModelEnum.CARD" class="jtable-card">
<div
v-if="_dataSource.length"
class="jtable-card-items"
:style="{gridTemplateColumns: `repeat(${column}, 1fr)`}"
>
<div
class="jtable-card-item"
v-for="(item, index) in _dataSource"
:key="index"
>
<CardBox :actions="actions" v-bind="cardProps">
<template #img>
<slot name="img">
<img :src="getImage('/device-product.png')" />
</slot>
</template>
<template #content>
<slot name="cardContent" :item="item" :index="index"></slot>
</template>
</CardBox>
</div>
</div>
<div v-else>
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</div>
<div v-else>
<a-table :rowSelection="rowSelection" :columns="[..._columns]" :dataSource="_dataSource" :pagination="false" :scroll="{ x: 1366 }">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-space>
<a-tooltip v-for="i in actions" :key="i.key" v-bind="i.tooltip">
<a-popconfirm v-if="i.popConfirm" v-bind="i.popConfirm">
<a>
{{i.text}}
</a>
</a-popconfirm>
<a v-else @click="i.onClick && i.onClick(record)">
{{i.text}}
</a>
</a-tooltip>
</a-space>
</template>
<template v-else-if="column.scopedSlots">
<slot :name="column.key" :row="record"></slot>
</template>
</template>
</a-table>
</div>
</div>
<div class="jtable-pagination" v-if="_dataSource.length && !noPagination">
<a-pagination
size="small"
:total="total"
:showQuickJumper="false"
:showSizeChanger="true"
v-model:current="pageIndex"
v-model:page-size="pageSize"
:show-total="(total, range) => `第 ${range[0]} - ${range[1]} 条/总共 ${total} 条`"
@change="pageChange"
:page-size-options="[12, 24, 48, 60, 100]"
/>
</div>
</div>
</a-spin>
</template>
<script setup lang="ts">
import { UnorderedListOutlined, AppstoreOutlined } from '@ant-design/icons-vue'
import type { TableProps } from 'ant-design-vue/es/table'
import type { TooltipProps } from 'ant-design-vue/es/tooltip'
import type { PopconfirmProps } from 'ant-design-vue/es/popconfirm'
import { Empty } from 'ant-design-vue'
import { CSSProperties } from 'vue';
import { getImage } from '@/utils/comm';
enum ModelEnum {
TABLE = 'TABLE',
CARD = 'CARD',
}
type RequestData = {
code: string;
result: {
data: Record<string, any>[] | undefined;
pageIndex: number;
pageSize: number;
total: number;
};
status: number;
} & Record<string, any>;
export interface ActionsType {
key: string;
text?: string;
disabled?: boolean;
permission?: boolean;
onClick?: (data: any) => void;
style?: CSSProperties;
tooltip?: TooltipProps;
popConfirm?: PopconfirmProps;
icon?: string;
}
interface JTableProps extends TableProps{
request?: (params: Record<string, any> & {
pageSize: number;
pageIndex: number;
}) => Promise<Partial<RequestData>>;
cardBodyClass?: string;
columns: Record<string, any>[];
params?: Record<string, any> & {
pageSize: number;
pageIndex: number;
};
model?: keyof typeof ModelEnum | undefined; // tablecard
actions?: ActionsType[];
noPagination?: boolean;
rowSelection?: TableProps['rowSelection'];
cardProps?: Record<string, any>;
dataSource?: Record<string, any>[];
}
// props
const props = withDefaults(defineProps<JTableProps>(), {
cardBodyClass: '',
request: undefined,
})
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE
const _model = ref<keyof typeof ModelEnum>(props.model ? props.model : ModelEnum.CARD); //
const column = ref<number>(4);
const _dataSource = ref<Record<string, any>[]>([])
const pageIndex = ref<number>(0)
const pageSize = ref<number>(6)
const total = ref<number>(0)
const _columns = ref<Record<string, any>[]>([])
const loading = ref<boolean>(true)
//
// const slotColumns = computed(() => props.columns.filter((item) => item.scopedSlots))
//
//
const modelChange = (type: keyof typeof ModelEnum) => {
_model.value = type
}
//
const handleSearch = async (_params?: Record<string, any>) => {
loading.value = true
if(props.request) {
const resp = await props.request({
pageSize: 12,
pageIndex: 1,
..._params
})
if(resp.status === 200){
//
if(resp.result?.data?.length === 0 && resp.result.total && resp.result.pageSize && resp.result.pageIndex) {
handleSearch({
..._params,
pageSize: pageSize.value,
pageIndex: pageIndex.value - 1,
})
} else {
_dataSource.value = resp.result?.data || []
pageIndex.value = resp.result?.pageIndex || 0
pageSize.value = resp.result?.pageSize || 6
total.value = resp.result?.total || 0
}
}
} else {
_dataSource.value = props?.dataSource || []
}
loading.value = false
}
const pageChange = (page: number, size: number) => {
handleSearch({
...props.params,
pageSize: size,
pageIndex: pageSize.value === size ? page : 1,
})
}
watchEffect(() => {
if(Array.isArray(props.actions) && props.actions.length) {
_columns.value = [...props.columns,
{
title: '操作',
key: 'action',
fixed: 'right',
width: 250
}
]
} else {
_columns.value = [...props.columns]
}
handleSearch(props.params)
})
</script>
<style lang="less" scoped>
.jtable-body {
width: 100%;
padding: 0 24px 24px;
background-color: white;
.jtable-body-header {
padding: 16px 0;
display: flex;
justify-content: space-between;
align-items: center;
.jtable-body-header-right {
display: flex;
gap: 8px;
.jtable-setting-item {
color: rgba(0, 0, 0, 0.75);
font-size: 16px;
cursor: pointer;
&:hover {
color: @primary-color-hover;
}
&.active {
color: @primary-color-active;
}
}
}
}
.jtable-content {
.jtable-card {
.jtable-card-items {
display: grid;
grid-gap: 26px;
// grid-template-columns: repeat(4, 1fr);
.jtable-card-item {
display: flex;
}
}
}
}
.jtable-pagination {
margin-top: 20px;
display: flex;
justify-content: flex-end;
/deep/ .ant-pagination-item {
display: none !important;
}
}
}
</style>

View File

@ -1,7 +1,8 @@
import { UnorderedListOutlined, AppstoreOutlined } from '@ant-design/icons-vue'
import styles from './index.module.less'
import { Space, Pagination, Table, Empty } from 'ant-design-vue'
import { Pagination, Table, Empty } from 'ant-design-vue'
import type { TableProps } from 'ant-design-vue/es/table'
enum ModelEnum {
TABLE = 'TABLE',
CARD = 'CARD',
@ -17,18 +18,15 @@ export declare type RequestData = {
};
status: number;
} & Record<string, any>;
// interface ColumnType extends
interface JTableProps extends TableProps{
// columns?: ColumnsType<RecordType>;
request: (params: Record<string, any> & {
pageSize?: number;
pageIndex?: number;
pageSize: number;
pageIndex: number;
}) => Promise<Partial<RequestData>>;
cardBodyClass?: string;
cardBodyClass: string;
}
const JTable = defineComponent<JTableProps>({
name: 'JTable',
slots: [
@ -38,10 +36,15 @@ const JTable = defineComponent<JTableProps>({
emits: [
'modelChange', // 切换卡片和表格
],
setup(props: JTableProps, { slots, emit }){
props: {
cardBodyClass: '',
request: undefined,
columns: []
} as any,
setup(props ,{ slots, emit }){
const model = ref<keyof typeof ModelEnum>(ModelEnum.CARD); // 模式切换
const column = ref<number>(3);
console.log(props)
console.log(props.columns, props.request)
const dataSource = ref<any[]>([
{
key: '1',
@ -81,6 +84,8 @@ const JTable = defineComponent<JTableProps>({
},
])
// 请求数据
onMounted(() => {
})

View File

@ -1,9 +1,10 @@
import type { App } from 'vue'
import AIcon from './AIcon'
import PermissionButton from './PermissionButton/index.vue'
import JTable from './Table/index'
import JTable from './Table/index.vue'
import TitleComponent from "./TitleComponent/index.vue";
import Form from './Form'
import Form from './Form';
import CardBox from './CardBox/index.vue';
export default {
install(app: App) {
@ -12,5 +13,6 @@ export default {
.component('JTable', JTable)
.component('TitleComponent', TitleComponent)
.component('Form', Form)
.component('CardBox', CardBox)
}
}

View File

@ -10,7 +10,6 @@ const router = createRouter({
router.beforeEach((to, from, next) => {
const token = LocalStore.get(TOKEN_KEY)
next() // 测试用, 可删除
if (token) {
next()
} else {

View File

@ -29,16 +29,16 @@ export default [
component: () => import('@/views/demo/index.vue')
},
{
path: '/bind',
path: '/account/center/bind',
component: () => import('@/views/account/Center/bind/index.vue')
},
{
path: '/iot/home',
component: () => import('@/views/iot/home/index.vue')
component: () => import('@/views/home/index.vue')
},
{
path: '/table',
component: () => import('@/views/table/index.vue')
component: () => import('@/views/demo/table/index.vue')
},
{
path: '/form',

View File

@ -1,240 +0,0 @@
/** 路由Code */
export enum MENUS_CODE {
'home' = 'home',
'Analysis/CPU' = 'Analysis/CPU',
'Analysis/DeviceChart' = 'Analysis/DeviceChart',
'Analysis/DeviceMessage' = 'Analysis/DeviceMessage',
'Analysis/Jvm' = 'Analysis/Jvm',
'Analysis/MessageChart' = 'Analysis/MessageChart',
'Analysis' = 'Analysis',
'cloud/Aliyun' = 'cloud/Aliyun',
'cloud/Ctwing' = 'cloud/Ctwing',
'cloud/DuerOS' = 'cloud/DuerOS',
'cloud/Onenet' = 'cloud/Onenet',
'device/Alarm' = 'device/Alarm',
'device/Category/Save' = 'device/Category/Save',
'device/Category' = 'device/Category',
'device/Command' = 'device/Command',
'device/DataSource' = 'device/DataSource',
'device/Instance' = 'device/Instance',
'device/Location' = 'device/Location',
'device/Product/Save' = 'device/Product/Save',
'device/Product' = 'device/Product',
'device/DashBoard' = 'device/DashBoard',
'device/components/Alarm/Edit' = 'device/components/Alarm/Edit',
'device/components/Alarm/Record' = 'device/components/Alarm/Record',
'device/components/Alarm/Setting' = 'device/components/Alarm/Setting',
'device/components/Alarm' = 'device/components/Alarm',
'device/components/Metadata/Base/Edit' = 'device/components/Metadata/Base/Edit',
'device/components/Metadata/Base' = 'device/components/Metadata/Base',
'device/components/Metadata/Cat' = 'device/components/Metadata/Cat',
'device/components/Metadata/Import' = 'device/components/Metadata/Import',
'device/components/Metadata' = 'device/components/Metadata',
'link/Certificate' = 'link/Certificate',
'link/Certificate/Detail' = 'link/Certificate/Detail',
'link/Gateway' = 'link/Gateway',
'link/Protocol/Debug' = 'link/Protocol/Debug',
'link/Protocol' = 'link/Protocol',
'link/Type' = 'link/Type',
'link/AccessConfig' = 'link/AccessConfig',
'link/DataCollect/Dashboard' = 'link/DataCollect/Dashboard',
'link/DataCollect/DataGathering' = 'link/DataCollect/DataGathering',
'link/DataCollect/IntegratedQuery' = 'link/DataCollect/IntegratedQuery',
'edge/Device' = 'edge/Device',
'edge/Resource' = 'edge/Resource',
'Log' = 'Log',
'media/Cascade' = 'media/Cascade',
'media/Cascade/Save' = 'media/Cascade/Save',
'media/Cascade/Channel' = 'media/Cascade/Channel',
'media/Config' = 'media/Config',
'media/Device' = 'media/Device',
'media/Device/Save' = 'media/Device/Save',
'media/Device/Channel' = 'media/Device/Channel',
'media/Device/Playback' = 'media/Device/Playback',
'media/Reveal' = 'media/Reveal',
'media/Stream' = 'media/Stream',
'media/Stream/Detail' = 'media/Stream/Detail',
'media/DashBoard' = 'media/DashBoard',
'notice/Type' = 'notice/Type',
'notice/Config' = 'notice/Config',
'media/SplitScreen' = 'media/SplitScreen',
'notice/Type/Config' = 'notice/Config',
'notice/Config/Detail' = 'notice/Config/Detail',
'notice/Template' = 'notice/Template',
'notice/Template/Detail' = 'notice/Template/Detail',
'rule-engine/DashBoard' = 'rule-engine/DashBoard',
'rule-engine/Instance' = 'rule-engine/Instance',
'rule-engine/SQLRule' = 'rule-engine/SQLRule',
'rule-engine/Scene' = 'rule-engine/Scene',
'rule-engine/Alarm/Log' = 'rule-engine/Alarm/Log',
'rule-engine/Alarm/Log/Detail' = 'rule-engine/Alarm/Log/Detail',
'rule-engine/Alarm/Config' = 'rule-engine/Alarm/Config',
'rule-engine/Scene/Save' = 'rule-engine/Scene/Save',
'rule-engine/Scene/Save2' = 'rule-engine/Scene/Save2',
'rule-engine/Alarm/Configuration' = 'rule-engine/Alarm/Configuration',
'rule-engine/Alarm/Configuration/Save' = 'rule-engine/Alarm/Configuration/Save',
'simulator/Device' = 'simulator/Device',
'system/DataSource' = 'system/DataSource',
'system/DataSource/Management' = 'system/DataSource/Management',
'system/Department/Assets' = 'system/Department/Assets',
'system/Department/Member' = 'system/Department/Member',
'system/Department' = 'system/Department',
'system/Menu' = 'system/Menu',
'system/Menu/Setting' = 'system/Menu/Setting',
'system/OpenAPI' = 'system/OpenAPI',
'system/Permission' = 'system/Permission',
'system/Role/Detail' = 'system/Role/Detail',
'system/Role' = 'system/Role',
'system/Tenant/Detail/Assets' = 'system/Tenant/Detail/Assets',
'system/Tenant/Detail/Info' = 'system/Tenant/Detail/Info',
'system/Tenant/Detail/Member' = 'system/Tenant/Detail/Member',
'system/Tenant/Detail/Permission' = 'system/Tenant/Detail/Permission',
'system/Tenant/Detail' = 'system/Tenant/Detail',
'system/Tenant' = 'system/Tenant',
'system/User' = 'system/User',
'system/Relationship' = 'system/Relationship',
'system/Basis' = 'system/Basis',
'user/Login' = 'user/Login',
'visualization/Category' = 'visualization/Category',
'visualization/Configuration' = 'visualization/Configuration',
'visualization/Screen' = 'visualization/Screen',
'device/Firmware' = 'device/Firmware',
'device/Firmware/Task' = 'device/Firmware/Task',
'device/Firmware/Task/Detail' = 'device/Firmware/Task/Detail',
'device/Instance/Detail/Config/Tags' = 'device/Instance/Detail/Config/Tags',
'device/Instance/Detail/Config' = 'device/Instance/Detail/Config',
'device/Instance/Detail/Functions' = 'device/Instance/Detail/Functions',
'device/Instance/Detail/Info' = 'device/Instance/Detail/Info',
'device/Instance/Detail/Log' = 'device/Instance/Detail/Log',
'device/Instance/Detail/MetadataLog/Event' = 'device/Instance/Detail/MetadataLog/Event',
'device/Instance/Detail/MetadataLog/Property' = 'device/Instance/Detail/MetadataLog/Property',
'device/Instance/Detail/Running' = 'device/Instance/Detail/Running',
'device/Instance/Detail' = 'device/Instance/Detail',
'device/Product/Detail/BaseInfo' = 'device/Product/Detail/BaseInfo',
'device/Product/Detail' = 'device/Product/Detail',
'link/AccessConfig/Detail' = 'link/AccessConfig/Detail',
'link/DashBoard' = 'link/DashBoard',
'system/Menu/Detail' = 'system/Menu/Detail',
'system/Department/Detail' = 'system/Department/Detail',
'link/Type/Detail' = 'link/Type/Detail',
'account/Center' = 'account/Center',
'account/NotificationSubscription' = 'account/NotificationSubscription',
'account/NotificationRecord' = 'account/NotificationRecord',
'account/Center/bind' = 'account/Center/bind',
'Northbound/DuerOS' = 'Northbound/DuerOS',
'Northbound/DuerOS/Detail' = 'Northbound/DuerOS/Detail',
'Northbound/AliCloud' = 'Northbound/AliCloud',
'Northbound/AliCloud/Detail' = 'Northbound/AliCloud/Detail',
'system/Platforms' = 'system/Platforms',
'system/Platforms/Api' = 'system/Platforms/Api',
'system/Platforms/View' = 'system/Platforms/View',
'system/Platforms/Setting' = 'system/Platforms/Setting',
'system/Apply' = 'system/Apply',
'system/Apply/Api' = 'system/Apply/Api',
'system/Apply/View' = 'system/Apply/View',
'system/License' = 'system/License',
'iot-card/Home' = 'iot-card/Home',
'iot-card/Platform' = 'iot-card/Platform',
'iot-card/Platform/Detail' = 'iot-card/Platform/Detail',
'iot-card/Recharge' = 'iot-card/Recharge',
'iot-card/Dashboard' = 'iot-card/Dashboard',
'iot-card/CardManagement' = 'iot-card/CardManagement',
'iot-card/Record' = 'iot-card/Record',
}
export type MENUS_CODE_TYPE = keyof typeof MENUS_CODE | string;
export enum BUTTON_PERMISSION_ENUM {
'add' = 'add',
'delete' = 'delete',
'import' = 'import',
'view' = 'view',
'export' = 'export',
'update' = 'update',
'action' = 'action',
'push' = 'push',
'assert' = 'assert',
'bind-user' = 'bind-user',
'active' = 'active',
'sync' = 'sync',
'channel' = 'channel',
'debug' = 'debug',
'log' = 'log',
'tigger' = 'tigger',
'empowerment' = 'empowerment',
'bind' = 'bind',
'edit' = 'edit', //资产权限编辑
'setting' = 'setting', //菜单配置
'password' = 'password', //重置密码
'api' = 'api', //查看api
'manage' = 'manage', //数据源-管理
'stop' = 'stop',
'restart' = 'restart',
'pay' = 'pay', //充值
}
// 调试按钮、通知记录、批量导出、批量导入、选择通道、推送、分配资产、绑定用户对应的ID是啥
export type CUSTOM_BUTTON = 'debug' | 'log' | 'channel' | 'assert' | 'bind-user';
export type BUTTON_PERMISSION = keyof typeof BUTTON_PERMISSION_ENUM | string | CUSTOM_BUTTON;
export const getDetailNameByCode = {
'system/Menu/Detail': '菜单详情',
'device/Product/Detail': '产品详情',
'device/Instance/Detail': '设备详情',
'device/Firmware/Task/Detail': '详情',
'system/Department/Detail': '组织详情',
'system/Role/Detail': '权限配置',
'link/Type/Detail': '网络组件详情',
'link/AccessConfig/Detail': '配置详情',
'media/Stream/Detail': '流媒体详情',
'rule-engine/Alarm/Log/Detail': '告警日志',
'Northbound/AliCloud/Detail': '阿里云详情',
'link/Certificate/Detail': '证书详情',
'iot-card/Platform/Detail': '平台对接详情',
};
// 开源版路由
export const CommunityCodeList = [
'account/Center',
'account/NotificationSubscription',
'account/NotificationRecord',
'system/Basis',
'system/User',
'system/Department',
'system/Department/Detail',
'system/Role',
'system/Role/Detail',
'system/Menu',
'system/Menu/Detail',
'system/Menu/Setting',
'system/Permission',
'system/Relationship',
'home',
'rule-engine/DashBoard',
'rule-engine/Alarm/Configuration',
'rule-engine/Alarm/Configuration/Save',
'rule-engine/Alarm/Log',
'rule-engine/Alarm/Log/Detail',
'device/DashBoard',
'device/Category',
'device/Instance',
'device/Instance/Detail',
'device/Product',
'device/Product/Detail',
'link/AccessConfig',
'link/AccessConfig/Detail',
'link/Protocol',
'link/DashBoard',
'Log',
'link/Type',
'link/Type/Detail',
'link/Certificate',
'link/Certificate/Detail',
'rule-engine/Scene',
'rule-engine/Scene/Save',
'notice/Config',
'notice/Config/Detail',
'notice/Template',
'notice/Template/Detail',
];

View File

@ -1,10 +1,9 @@
import { defineStore } from "pinia";
import type { MENUS_CODE_TYPE, BUTTON_PERMISSION } from '@/router/router'
export const usePermissionStore = defineStore({
id: 'permission',
state: () => ({
permissions: {} as {[key: MENUS_CODE_TYPE]: BUTTON_PERMISSION},
permissions: {} as {[key: string]: string},
}),
getters: {
check(state) {

View File

@ -2,4 +2,6 @@ export const BASE_API_PATH = import.meta.env.VITE_APP_BASE_API
export const TOKEN_KEY = 'X-Access-Token'
export const Version_Code = 'version_code'
export const Version_Code = 'version_code'
export const NETWORK_CERTIFICATE_UPLOAD = '/network/certificate/upload'

View File

@ -0,0 +1,102 @@
<template>
<div class="box">
<JTable
:columns="[
{
title: '名称',
dataIndex: 'name',
key: 'name',
},
{
title: 'ID',
dataIndex: 'id',
key: 'id',
scopedSlots: true
},
{
title: '分类',
dataIndex: 'classifiedName',
key: 'classifiedName',
},
]"
:actions="actions"
:request="request"
:rowSelection="rowSelection"
>
<template #headerTitle>
<a-button type="primary">新增</a-button>
</template>
<template #cardContent="slotProps">
<h3>{{slotProps.item.name}}</h3>
<a-row>
<a-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<div>直连设备</div>
</a-col>
<a-col :span="12">
<div class="card-item-content-text">
产品名称
</div>
<div>测试固定地址</div>
</a-col>
</a-row>
</template>
<template #id="slotProps">
<a>{{slotProps.row.id}}</a>
</template>
</JTable>
</div>
</template>
<script setup lang="ts">
import server from "@/utils/request";
import type { ActionsType } from '@/components/Table/index.vue'
import { getImage } from '@/utils/comm';
import type { TableProps, TableColumnType } from 'ant-design-vue';
const request = (data: any) => server.post(`/device-product/_query`, data)
const actions: ActionsType[] = [
{
key: 'edit',
// disabled: true,
text: "编辑",
tooltip: {
title: '编辑'
},
// component: <UnorderedListOutlined />
},
{
key: 'delete',
disabled: true,
text: "删除",
tooltip: {
title: '删除'
},
popConfirm: {
title: '确认删除?'
}
}
]
const rowSelection: TableProps['rowSelection'] = {
onChange: (selectedRowKeys: string[], selectedRows: any[]) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
},
getCheckboxProps: (record: any) => ({
disabled: record.name === 'Disabled User',
name: record.name,
}),
};
</script>
<style lang="less" scoped>
.box {
padding: 20px;
background: #f0f2f5;
}
</style>

View File

@ -42,6 +42,10 @@ import Pie from './Pie.vue';
const cpu = ref('20%');
const jvm = ref('31%');
const getData = ()=>{
}
const jumpPage = () => {};
</script>

View File

@ -186,5 +186,5 @@ const opsStepDetails = [
linkUrl: '/a',
auth: false,
},
];
] as recommendList[];
</script>

View File

@ -27,6 +27,7 @@ import BasicCountCard from '../BasicCountCard.vue';
import PlatformPicCard from '../PlatformPicCard.vue';
import StepCard from '../StepCard.vue';
import {recommendList} from '../../index'
// import {getImage} from '@/utils/comm'
// -
@ -93,7 +94,7 @@ const stepDetails = [
linkUrl: '/a',
auth: false,
},
];
] as recommendList[];
</script>
<style lang="less" scoped>

View File

@ -25,9 +25,22 @@
</template>
<script setup lang="ts">
import { getDeviceCount_api, getProductCount_api } from '@/api/home';
const projectNum = ref(0);
const deviceNum = ref(0);
onMounted(() => {
getData();
});
const getData = () => {
getDeviceCount_api().then((resp) => {
deviceNum.value = resp.result;
});
getProductCount_api().then((resp) => {
projectNum.value = resp.result;
});
};
const jumpPage = () => {};
</script>

View File

@ -26,6 +26,9 @@ import BootCard from '../BootCard.vue';
import DeviceCountCard from '../DeviceCountCard.vue';
import PlatformPicCard from '../PlatformPicCard.vue';
import StepCard from '../StepCard.vue';
import {recommendList} from '../../index'
// import {getImage} from '@/utils/comm'
// -
@ -90,7 +93,7 @@ const stepDetails = [
linkUrl: '/a',
auth: false,
},
];
] as recommendList[];
</script>
<style lang="less" scoped>

View File

@ -4,8 +4,9 @@
<script setup lang="ts">
import * as echarts from 'echarts';
import { ComponentInternalInstance } from 'vue';
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const props = defineProps({
chartRef: String,
@ -50,7 +51,7 @@ watch(options, () => {
});
const initChart = () => {
nextTick(() => {
const myChart = echarts.init(proxy.$refs[props.chartRef]);
const myChart = echarts.init(proxy?.$refs[props.chartRef as string] as HTMLElement);
myChart.clear();
myChart.setOption(options.value);

View File

@ -11,12 +11,8 @@
</h5>
<div class="box-list">
<div
class="list-item"
v-for="item in dataList"
@click="jumpPage(item)"
>
<div class="box-top">
<div class="list-item" v-for="item in dataList">
<div class="box-top" @click="jumpPage(item)">
<span class="top-title">{{ item.title }}</span>
<img :src="item.iconUrl" alt="" />
</div>
@ -25,7 +21,10 @@
</div>
<div class="dialogs">
<AccessMethodDialog :open-number="openAccess" />
<AccessMethodDialog
:open-number="openAccess"
@confirm="againJumpPage"
/>
</div>
</a-card>
</template>
@ -39,6 +38,11 @@ import AccessMethodDialog from './dialogs/AccessMethodDialog.vue';
import { recommendList } from '../index';
type rowType = {
params: object;
linkUrl: string;
};
const props = defineProps({
cardTitle: String,
tooltip: String,
@ -49,15 +53,25 @@ const router = useRouter();
const { cardTitle, tooltip, dataList } = toRefs(props);
const openAccess = ref<number>(0);
const openFunc = ref<number>(0);
let selectRow: recommendList | rowType = {
params: {},
linkUrl: '',
};
//
const jumpPage = (row: recommendList) => {
if (!row.auth) return message.warning('暂无权限,请联系管理员');
else if (row.dialogTag == 'accessMethod') return (openAccess.value += 1);
selectRow = row; // 使
if (row.dialogTag == 'accessMethod') return (openAccess.value += 1);
else if (row.dialogTag === 'funcTest') return (openFunc.value += 1);
else if (row.linkUrl) {
router.push(`${row.linkUrl}${objToParams(row.params || {})}`);
}
};
//
const againJumpPage = (paramsSource: object) => {
const params = { ...(selectRow.params || {}), ...paramsSource };
router.push(`${selectRow.linkUrl}${objToParams(params || {})}`);
};
const objToParams = (source: object): string => {
if (Object.prototype.toString.call(source) === '[object Object]') {

View File

@ -0,0 +1,98 @@
<template>
<div ref="modal" class="access-method-dialog-container"></div>
<a-modal
v-model:visible="visible"
title="选择产品"
style="width: 700px"
@ok="handleOk"
show-search
:filter-option="filterOption"
:getContainer="getContainer"
:maskClosable="false"
>
<a-form :model="form" name="basic" autocomplete="off" layout="vertical">
<a-form-item
label="产品"
name="productId"
:rules="[{ required: true, message: '该字段是必填字段' }]"
>
<a-select
v-model:value="form.productId"
style="width: 100%"
:options="productList"
>
</a-select>
</a-form-item>
</a-form>
<template #footer>
<a-button key="back" @click="visible = false">取消</a-button>
<a-button key="submit" type="primary" @click="handleOk"
>确认</a-button
>
</template>
</a-modal>
</template>
<script setup lang="ts">
import { ComponentInternalInstance } from 'vue';
import { getProductList_api } from '@/api/home';
import { productItem } from '../../index';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const props = defineProps({
openNumber: Number,
});
const emits = defineEmits(['confirm']);
const visible = ref<boolean>(false);
const form = ref({
productId: '',
});
const productList = ref<[productItem] | []>([]);
const getContainer = () => proxy?.$refs.modal as HTMLElement;
const getOptions = () => {
getProductList_api().then((resp) => {
productList.value = resp.result
.filter((i: any) => !i?.accessId)
.map((item: { name: any; id: any }) => ({
label: item.name,
value: item.id,
})) as [productItem];
});
};
const handleOk = () => {
emits('confirm', form.value);
visible.value = false;
};
const filterOption = (input: string, option: any) => {
return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
watch(
() => props.openNumber,
() => {
visible.value = true;
form.value.productId = '';
getOptions();
},
);
</script>
<style lang="less" scoped>
.access-method-dialog-container {
:deep(.ant-modal-body) {
.ant-form {
.ant-form-item-label {
color: green;
.ant-form-item-required {
&::before {
position: absolute;
left: 30px;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,135 @@
<template>
<div ref="modal" class="func-test-dialog-container"></div>
<a-modal
v-model:visible="visible"
title="选择产品"
style="width: 700px"
@ok="handleOk"
:getContainer="getContainer"
:maskClosable="false"
>
<div class="search">
<a-select
v-model:value="form.key"
style="width: 100%"
:options="productList"
/>
<a-select
v-model:value="form.relation"
style="width: 100%"
:options="productList"
/>
<a-input v-model:value="form.keyValue" allow-clear />
<a-button type="primary" @click="clickSearch">
<template #icon><SearchOutlined /></template>
搜索
</a-button>
<a-button type="primary" @click="clickReset">
<template #icon><reload-outlined /></template>
重置
</a-button>
</div>
<a-table
:columns="columns"
:data-source="tableData"
:row-selection="{
onChange: (selectedRowKeys, selectedRows) =>
(selectItem = selectedRows),
type: 'radio',
}"
>
</a-table>
<template #footer>
<a-button key="back" @click="visible = false">取消</a-button>
<a-button key="submit" type="primary" @click="handleOk"
>确认</a-button
>
</template>
</a-modal>
</template>
<script setup lang="ts">
import { ComponentInternalInstance } from 'vue';
import { SearchOutlined, ReloadOutlined } from '@ant-design/icons-vue';
import { productItem, deviceInfo } from '../../index';
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const emits = defineEmits(['confirm']);
const props = defineProps({
openNumber: Number,
});
//
const visible = ref<boolean>(false);
const getContainer = () => proxy?.$refs.modal as HTMLElement;
const handleOk = () => {
emits('confirm', form.value);
visible.value = false;
};
watch(
() => props.openNumber,
() => {
clickReset();
getOptions();
clickSearch();
visible.value = true;
},
);
//
const form = ref({
key: '',
relation: '',
keyValue: '',
});
const productList = ref<[productItem] | []>([]);
const getOptions = () => {
productList.value = [];
};
const clickSearch = ()=>{
}
const clickReset = () => {
Object.entries(form.value).forEach(([prop]) => {
form.value[prop] = '';
});
};
//
const columns = [
{
name: 'deviceId',
dataIndex: 'deviceId',
key: 'deviceId',
},
{
name: 'deviceName',
dataIndex: 'deviceName',
key: 'deviceName',
},
{
name: 'productName',
dataIndex: 'productName',
key: 'productName',
},
{
name: 'createTime',
dataIndex: 'createTime',
key: 'createTime',
},
{
name: 'status',
dataIndex: 'status',
key: 'status',
},
];
const tableData = ref<deviceInfo[]>([]);
const selectItem: deviceInfo | {} = {};
const getList = () => {};
</script>
<style lang="scss" scoped></style>

View File

@ -12,4 +12,12 @@ export interface recommendList {
export interface productItem {
label: string;
value: string
}
export interface deviceInfo {
deviceId: string,
deviceName: string,
productName: string,
createTime: string,
status: boolean
}

View File

@ -6,7 +6,8 @@
<!-- <InitHome /> -->
<!-- <DeviceHome /> -->
<!-- <DevOpsHome /> -->
<ComprehensiveHome />
<!-- <ComprehensiveHome /> -->
<ApiPage />
</div>
</div>
</template>
@ -16,6 +17,7 @@ import InitHome from './components/InitHome/index.vue';
import DeviceHome from './components/DeviceHome/index.vue';
import DevOpsHome from './components/DevOpsHome/index.vue';
import ComprehensiveHome from './components/ComprehensiveHome/index.vue';
import ApiPage from '@/views/system/apiPage/index.vue'
</script>

View File

@ -0,0 +1,845 @@
/**
*
*/
export enum ROLEKEYS {
'device' = 'device',
'link' = 'link',
'complex' = 'complex',
}
export type roleKeysType = keyof typeof ROLEKEYS;
export const RoleData = {
[ROLEKEYS.device]: {
name: '设备接入岗',
description: '该角色负责设备接入模块的维护管理',
state: { text: '正常', value: 'enabled' },
},
[ROLEKEYS.link]: {
name: '运维管理岗',
description: '该角色负责系统运维模块的维护管理',
state: { text: '正常', value: 'enabled' },
},
[ROLEKEYS.complex]: {
name: '综合管理岗',
description: '该角色负责系统运维和设备接入模块的维护管理',
state: { text: '正常', value: 'enabled' },
},
};
export default {
[ROLEKEYS.device]: [
{
id: '1-3-2',
parentId: '1-3',
path: 'T4zX-b4q8-o7Jy',
sortIndex: 2,
level: 1,
name: '产品',
code: 'device/Product',
icon: 'icon-chanpin',
url: '/iot/device/Product',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'update',
name: '编辑',
enabled: true,
granted: true,
},
{ id: 'action', name: '启/禁用', enabled: true, granted: true },
{
id: 'export',
name: '导出',
enabled: true,
granted: true,
},
{ id: 'import', name: '导入', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
accessSupport: { text: '支持', value: 'support' },
assetType: 'product',
assetAccesses: [
{
supportId: 'ignore',
name: '全部数据',
enabled: false,
granted: false,
},
{ supportId: 'creator', name: '自己创建的', enabled: false, granted: false },
{
supportId: 'org',
name: '所在组织',
enabled: false,
granted: false,
},
{
supportId: 'org-include-children',
name: '所在组织及下级组织',
enabled: false,
granted: false,
},
],
options: { switch: true },
createTime: 1659344075524,
accessDescription: '此菜单支持数据权限控制',
granted: true,
},
{
id: '1-3-3',
parentId: '1-3',
path: 'T4zX-b4q8-xYd0',
sortIndex: 3,
level: 1,
name: '设备',
code: 'device/Instance',
icon: 'icon-shebei',
url: '/iot/device/Instance',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'export',
name: '导出',
enabled: true,
granted: true,
},
{ id: 'import', name: '导入', enabled: true, granted: true },
{
id: 'update',
name: '编辑',
enabled: true,
granted: true,
},
{ id: 'action', name: '启/禁用', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
accessSupport: { text: '支持', value: 'support' },
assetType: 'device',
assetAccesses: [
{
supportId: 'ignore',
name: '全部数据',
enabled: false,
granted: false,
},
{ supportId: 'creator', name: '自己创建的', enabled: false, granted: false },
{
supportId: 'org',
name: '所在组织',
enabled: false,
granted: false,
},
{
supportId: 'org-include-children',
name: '所在组织及下级组织',
enabled: false,
granted: false,
},
],
options: { switch: true },
createTime: 1659344075524,
accessDescription: '此菜单支持数据权限控制',
granted: true,
},
{
id: '1-3-4',
parentId: '1-3',
path: 'T4zX-b4q8-8ZFx',
sortIndex: 4,
level: 3,
name: '产品分类',
code: 'device/Category',
icon: 'icon-chanpinfenlei1',
url: '/iot/device/Category',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'update', name: '编辑', enabled: true, granted: true },
{
id: 'add',
name: '新增',
enabled: true,
granted: true,
},
],
assetAccesses: [],
options: { switch: true },
createTime: 1659344075524,
granted: true,
},
],
[ROLEKEYS.link]: [
{
id: '1-4-2',
parentId: '1-4',
path: 'T4zX-A0TC-UlSD',
sortIndex: 2,
level: 3,
name: '设备接入网关',
code: 'link/AccessConfig',
icon: 'icon-wangguanzishebei',
url: '/iot/link/accessConfig',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'action', name: '启/禁用', enabled: true, granted: true },
{
id: 'add',
name: '新增',
enabled: true,
granted: true,
},
{ id: 'update', name: '编辑', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-3',
parentId: '1-4',
path: 'T4zX-A0TC-ctFm',
sortIndex: 3,
level: 3,
name: '协议管理',
code: 'link/Protocol',
icon: 'icon-tongzhiguanli',
url: '/iot/link/protocol',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'action',
name: '启/禁用',
enabled: true,
granted: true,
},
{ id: 'delete', name: '删除', enabled: true, granted: true },
{
id: 'update',
name: '编辑',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-5',
parentId: '1-4',
path: 'T4zX-A0TC-fDic',
sortIndex: 5,
level: 3,
name: '网络组件',
code: 'link/Type',
icon: 'icon-wangluozujian',
url: '/iot/link/type',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'action',
name: '启/禁用',
enabled: true,
granted: true,
},
{ id: 'delete', name: '删除', enabled: true, granted: true },
{
id: 'add',
name: '新增',
enabled: true,
granted: true,
},
{ id: 'update', name: '编辑', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-6',
parentId: '1-4',
path: 'T4zX-A0TC-bBs5',
sortIndex: 6,
level: 3,
name: '证书管理',
code: 'link/Certificate',
icon: 'icon-rizhifuwu',
url: '/iot/link/Certificate',
buttons: [
{ id: 'delete', name: '删除', enabled: true, granted: true },
{
id: 'update',
name: '编辑',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-7',
parentId: '1-4',
path: 'T4zX-A0TC-VilV',
sortIndex: 7,
level: 3,
name: '流媒体服务',
code: 'media/Stream',
icon: 'icon-xuanzetongdao1',
url: '/iot/link/Stream',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'update', name: '编辑', enabled: true, granted: true },
{
id: 'add',
name: '新增',
enabled: true,
granted: true,
},
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-8-1',
parentId: '1-4-8',
path: 'T4zX-A0TC-GIE8-3Op3',
sortIndex: 1,
level: 4,
name: 'OPC UA',
code: 'link/Channel/Opcua',
icon: 'icon-zhilianshebei',
url: '/iot/link/Channel/Opcua',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'action',
name: '启/禁用',
enabled: true,
granted: true,
},
{ id: 'update', name: '编辑', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-8-2',
parentId: '1-4-8',
path: 'T4zX-A0TC-GIE8-79SB',
sortIndex: 2,
level: 4,
name: 'Modbus',
code: 'link/Channel/Modbus',
icon: 'icon-changjingliandong',
url: '/iot/link/Channel/Modbus',
buttons: [
{ id: 'update', name: '编辑', enabled: true, granted: true },
{
id: 'action',
name: '启/禁用',
enabled: true,
granted: true,
},
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-9',
parentId: '1-4',
path: 'T4zX-A0TC-BFum',
sortIndex: 9999,
level: 1,
name: '远程升级',
code: 'device/Firmware',
icon: 'icon-wangluozujian',
url: '/iot/link/firmware',
buttons: [
{ id: 'update', name: '编辑', enabled: true, granted: true },
{
id: 'action',
name: '启/禁用',
enabled: true,
granted: true,
},
{ id: 'delete', name: '删除', enabled: true, granted: true },
{
id: 'add',
name: '新增',
enabled: true,
granted: true,
},
],
accessSupport: { text: '不支持', value: 'unsupported' },
assetAccesses: [],
options: {},
createTime: 1659344075524,
accessDescription: '此菜单不支持数据权限控制',
granted: true,
},
],
[ROLEKEYS.complex]: [
{
id: '1-3-2',
parentId: '1-3',
path: 'T4zX-b4q8-o7Jy',
sortIndex: 2,
level: 1,
name: '产品',
code: 'device/Product',
icon: 'icon-chanpin',
url: '/iot/device/Product',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'update',
name: '编辑',
enabled: true,
granted: true,
},
{ id: 'action', name: '启/禁用', enabled: true, granted: true },
{
id: 'export',
name: '导出',
enabled: true,
granted: true,
},
{ id: 'import', name: '导入', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
accessSupport: { text: '支持', value: 'support' },
assetType: 'product',
assetAccesses: [
{
supportId: 'ignore',
name: '全部数据',
enabled: false,
granted: false,
},
{ supportId: 'creator', name: '自己创建的', enabled: false, granted: false },
{
supportId: 'org',
name: '所在组织',
enabled: false,
granted: false,
},
{
supportId: 'org-include-children',
name: '所在组织及下级组织',
enabled: false,
granted: false,
},
],
options: { switch: true },
createTime: 1659344075524,
accessDescription: '此菜单支持数据权限控制',
granted: true,
},
{
id: '1-3-3',
parentId: '1-3',
path: 'T4zX-b4q8-xYd0',
sortIndex: 3,
level: 1,
name: '设备',
code: 'device/Instance',
icon: 'icon-shebei',
url: '/iot/device/Instance',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'export',
name: '导出',
enabled: true,
granted: true,
},
{ id: 'import', name: '导入', enabled: true, granted: true },
{
id: 'update',
name: '编辑',
enabled: true,
granted: true,
},
{ id: 'action', name: '启/禁用', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
accessSupport: { text: '支持', value: 'support' },
assetType: 'device',
assetAccesses: [
{
supportId: 'ignore',
name: '全部数据',
enabled: false,
granted: false,
},
{ supportId: 'creator', name: '自己创建的', enabled: false, granted: false },
{
supportId: 'org',
name: '所在组织',
enabled: false,
granted: false,
},
{
supportId: 'org-include-children',
name: '所在组织及下级组织',
enabled: false,
granted: false,
},
],
options: { switch: true },
createTime: 1659344075524,
accessDescription: '此菜单支持数据权限控制',
granted: true,
},
{
id: '1-3-4',
parentId: '1-3',
path: 'T4zX-b4q8-8ZFx',
sortIndex: 4,
level: 3,
name: '产品分类',
code: 'device/Category',
icon: 'icon-chanpinfenlei1',
url: '/iot/device/Category',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'update', name: '编辑', enabled: true, granted: true },
{
id: 'add',
name: '新增',
enabled: true,
granted: true,
},
],
assetAccesses: [],
options: { switch: true },
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-2',
parentId: '1-4',
path: 'T4zX-A0TC-UlSD',
sortIndex: 2,
level: 3,
name: '设备接入网关',
code: 'link/AccessConfig',
icon: 'icon-wangguanzishebei',
url: '/iot/link/accessConfig',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'action', name: '启/禁用', enabled: true, granted: true },
{
id: 'add',
name: '新增',
enabled: true,
granted: true,
},
{ id: 'update', name: '编辑', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-3',
parentId: '1-4',
path: 'T4zX-A0TC-ctFm',
sortIndex: 3,
level: 3,
name: '协议管理',
code: 'link/Protocol',
icon: 'icon-tongzhiguanli',
url: '/iot/link/protocol',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'action',
name: '启/禁用',
enabled: true,
granted: true,
},
{ id: 'delete', name: '删除', enabled: true, granted: true },
{
id: 'update',
name: '编辑',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-5',
parentId: '1-4',
path: 'T4zX-A0TC-fDic',
sortIndex: 5,
level: 3,
name: '网络组件',
code: 'link/Type',
icon: 'icon-wangluozujian',
url: '/iot/link/type',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'action',
name: '启/禁用',
enabled: true,
granted: true,
},
{ id: 'delete', name: '删除', enabled: true, granted: true },
{
id: 'add',
name: '新增',
enabled: true,
granted: true,
},
{ id: 'update', name: '编辑', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-6',
parentId: '1-4',
path: 'T4zX-A0TC-bBs5',
sortIndex: 6,
level: 3,
name: '证书管理',
code: 'link/Certificate',
icon: 'icon-rizhifuwu',
url: '/iot/link/Certificate',
buttons: [
{ id: 'delete', name: '删除', enabled: true, granted: true },
{
id: 'update',
name: '编辑',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-7',
parentId: '1-4',
path: 'T4zX-A0TC-VilV',
sortIndex: 7,
level: 3,
name: '流媒体服务',
code: 'media/Stream',
icon: 'icon-xuanzetongdao1',
url: '/iot/link/Stream',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'update', name: '编辑', enabled: true, granted: true },
{
id: 'add',
name: '新增',
enabled: true,
granted: true,
},
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-8-1',
parentId: '1-4-8',
path: 'T4zX-A0TC-GIE8-3Op3',
sortIndex: 1,
level: 4,
name: 'OPC UA',
code: 'link/Channel/Opcua',
icon: 'icon-zhilianshebei',
url: '/iot/link/Channel/Opcua',
buttons: [
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'action',
name: '启/禁用',
enabled: true,
granted: true,
},
{ id: 'update', name: '编辑', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-8-2',
parentId: '1-4-8',
path: 'T4zX-A0TC-GIE8-79SB',
sortIndex: 2,
level: 4,
name: 'Modbus',
code: 'link/Channel/Modbus',
icon: 'icon-changjingliandong',
url: '/iot/link/Channel/Modbus',
buttons: [
{ id: 'update', name: '编辑', enabled: true, granted: true },
{
id: 'action',
name: '启/禁用',
enabled: true,
granted: true,
},
{ id: 'view', name: '查看', enabled: true, granted: true },
{
id: 'delete',
name: '删除',
enabled: true,
granted: true,
},
{ id: 'add', name: '新增', enabled: true, granted: true },
],
assetAccesses: [],
options: {},
createTime: 1659344075524,
granted: true,
},
{
id: '1-4-9',
parentId: '1-4',
path: 'T4zX-A0TC-BFum',
sortIndex: 9999,
level: 1,
name: '远程升级',
code: 'device/Firmware',
icon: 'icon-wangluozujian',
url: '/iot/link/firmware',
buttons: [
{ id: 'update', name: '编辑', enabled: true, granted: true },
{
id: 'action',
name: '启/禁用',
enabled: true,
granted: true,
},
{ id: 'delete', name: '删除', enabled: true, granted: true },
{
id: 'add',
name: '新增',
enabled: true,
granted: true,
},
],
accessSupport: { text: '不支持', value: 'unsupported' },
assetAccesses: [],
options: {},
createTime: 1659344075524,
accessDescription: '此菜单不支持数据权限控制',
granted: true,
},
],
};

View File

@ -0,0 +1,33 @@
/** 初始化数据提交表单 */
export interface modalState {
host: string; // 本地地址
port: string; // 本地端口
publicHost: string; // 公网地址
publicPort: number | null; // 公网端口
rules: Record<string, Rule[]>;
}
/**基本信息表单 */
export interface formState {
title: string; // 系统名称
headerTheme: string; // 主题色
apikey: string; // 高德 API key
basePath: string; // 系统后台访问的URL
logo: string; // 系统logo
icon: string; // 浏览器页签
rulesFrom: Record<string, Rule[]>;
}
/**
* logo上传表当
*/
export interface logoState {
logoValue: string;
logoLoading: boolean;
inLogo: boolean;
inIcon: boolean;
inBackground: boolean;
iconValue: string;
backValue: string;
handleChangeLogo:(url: string) => void
}

File diff suppressed because it is too large Load Diff

View File

@ -1,55 +0,0 @@
<template>
<a-modal
v-model:visible="visible"
title="选择产品"
style="width: 500px"
@ok="handleOk"
show-search
:filter-option="filterOption"
>
<a-select
v-model:value="productId"
style="width: 100%"
:options="productList"
>
</a-select>
<template #footer>
<a-button key="back" @click="visible = false">取消</a-button>
<a-button key="submit" type="primary" @click="handleOk"
>确认</a-button
>
</template>
</a-modal>
</template>
<script setup lang="ts">
import { productItem } from '../../index';
const props = defineProps({
openNumber: Number,
});
const emits = defineEmits(['confirm']);
const { openNumber } = toRefs(props);
const visible = ref<boolean>(false);
const productId = ref<string>('');
const productList = ref<[productItem] | []>([]);
const getOptions = () => {
productList.value = [];
};
const handleOk = () => {
emits('confirm', productId.value);
visible.value = false;
};
const filterOption = (input: string, option: any) => {
return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
watch(openNumber, () => {
visible.value = true;
productId.value = '';
getOptions();
});
</script>
<style scoped></style>

View File

@ -1,88 +1,91 @@
<template>
<a-spin :spinning="loading">
<div>
<a-textarea
:rows="4"
@change="textChange"
v-model="keystoreBase64"
:placeholder=placeholder
/>
<a-upload
accept=".pem"
listType="text"
:action="action"
:headers="headers"
:showUploadList="false"
@change="handleChange"
>
<a-button style="margin-top: 10px">
<upload-outlined></upload-outlined>
上传文件</a-button>
</a-upload>
</div>
</a-spin>
<a-spin :spinning="loading">
<div>
<a-textarea
:rows="4"
@change="textChange"
v-model:value="keystoreBase64"
:placeholder="placeholder"
/>
<a-upload
accept=".pem"
listType="text"
:action="`${BASE_API_PATH}${NETWORK_CERTIFICATE_UPLOAD}`"
:headers="{
[TOKEN_KEY]: LocalStore.get(TOKEN_KEY),
}"
:showUploadList="false"
@change="handleChange"
>
<a-button style="margin-top: 10px">
<upload-outlined />
上传文件</a-button
>
</a-upload>
</div>
</a-spin>
</template>
<script>
// import storage from 'store'
// import { ACCESS_TOKEN } from '@/store/mutation-types'
// import { ACCESS_TOKEN_KEY } from '@/utils/consts'
<script setup lang="ts" name="CertificateFile">
import { UploadOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import type { UploadChangeParam } from 'ant-design-vue';
import { LocalStore } from '@/utils/comm';
import {
BASE_API_PATH,
TOKEN_KEY,
NETWORK_CERTIFICATE_UPLOAD,
} from '@/utils/variable';
import type { UploadProps } from 'ant-design-vue';
export default {
name: 'CertificateFile',
data () {
return {
keystoreBase64: '',
loading: false,
action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
headers:{
authorization: 'authorization-text',
}
// action: process.env.VUE_APP_BASE_API + `/network/certificate/upload`,
// headers: {
// [ACCESS_TOKEN_KEY]: storage.get(ACCESS_TOKEN)
// }
}
},
model: {
prop: 'value',
event: 'change'
},
props: {
value: {
type: String,
default: () => ''
const emit = defineEmits(['update:modelValue', 'change']);
const props = defineProps({
name: {
type: String,
default: () => '',
},
modelValue: {
type: String,
default: () => '',
},
placeholder: {
type: String,
default: () => ''
}
},
watch: {
value: {
handler (v) {
this.keystoreBase64 = v
}
}
},
methods: {
handleChange (info) {
this.loading = true
if (info.file.status === 'done') {
this.$message.success('上传成功!')
const result = info.file.response?.result
this.loading = false
this.$emit('change', result)
}
type: String,
default: () => '',
},
textChange (val) {
this.$emit('change', val)
});
const keystoreBase64 = ref(props.modelValue);
const loading = ref(false);
const handleChange = (info: UploadChangeParam) => {
loading.value = true;
if (info.file.status === 'done') {
message.success('上传成功!');
const result = info.file.response?.result;
keystoreBase64.value = result;
console.log(1114, result);
loading.value = false;
emit('change', result);
emit('update:modelValue', result);
}
}
}
};
const textChange = (val: any) => {
val.name = props.name;
emit('change', val);
// emit('update:modelValue', val);
};
watch(
() => props.modelValue,
(v) => {
keystoreBase64.value = v;
},
{
deep: true,
immediate: true,
},
);
</script>
<style lang="less" scoped>
</style>
<style lang="less" scoped></style>

View File

@ -11,18 +11,9 @@
:wrapper-col="{ span: 16 }"
autocomplete="off"
@finish="onFinish"
@finishFailed="onFinishFailed"
:rules="formRules"
>
<a-form-item
label="证书标准"
name="type"
:rules="[
{
required: true,
message: '请选择证书标准',
},
]"
>
<a-form-item label="证书标准" name="type">
<a-radio-group v-model:value="formData.type">
<a-radio-button
class="form-radio-button"
@ -33,46 +24,25 @@
</a-radio-group>
</a-form-item>
<a-form-item
label="证书名称"
name="name"
:rules="[
{
required: true,
message: '请输入证书名称',
},
]"
>
<a-form-item label="证书名称" name="name">
<a-input
placeholder="请输入证书名称"
v-model:value="formData.name"
/>
</a-form-item>
<a-form-item
label="证书文件"
name="cert"
:rules="[
{
required: true,
message: '上传证书文件',
},
]"
>
<a-form-item label="证书文件" name="cert">
<CertificateFile
name="cert"
v-model:modelValue="formData.cert"
@change="changeFileValue"
placeholder='证书格式以"-----BEGIN CERTIFICATE-----"开头,以"-----END CERTIFICATE-----"结尾"'
/>
</a-form-item>
<a-form-item
label="证书私钥"
name="key"
:rules="[
{
required: true,
message: '请上传证书私钥',
},
]"
>
<a-form-item label="证书私钥" name="key">
<CertificateFile
name="key"
v-model:modelValue="formData.key"
@change="changeFileValue"
placeholder='证书私钥格式以"-----BEGIN (RSA|EC) PRIVATE KEY-----"开头,以"-----END(RSA|EC) PRIVATE KEY-----"结尾。'
/>
</a-form-item>
@ -117,46 +87,73 @@
</a-row>
</a-card>
</template>
<!-- export const ACCESS_TOKEN_KEY = 'X-Access-Token' -->
<!-- export const ACCESS_TOKEN = 'device_token' -->
<script lang="ts" setup name="CertificateDetail">
import { message } from 'ant-design-vue';
import { getImage } from '@/utils/comm';
import CertificateFile from './CertificateFile.vue';
import type { UploadChangeParam } from 'ant-design-vue';
import { LocalStore } from '@/utils/comm';
import {
BASE_API_PATH,
TOKEN_KEY,
NETWORK_CERTIFICATE_UPLOAD,
} from '@/utils/variable';
import { save } from '@/api/link/certificate';
const loading = ref(false);
const formData = reactive({
type: 'common',
name: '',
configs: {
cert: '',
key: '',
},
cert: '',
key: '',
// configs: {
// cert: '',
// key: '',
// },
description: '',
});
const onFinish = (values: any) => {
console.log('Success:', values);
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
const formRules = {
type: [{ required: true, message: '请选择证书标准', trigger: 'blur' }],
name: [
{ required: true, message: '请输入证书名称', trigger: 'blur' },
{ max: 64, message: '最多可输入64个字符' },
],
cert: [{ required: true, message: '请输入或上传文件', trigger: 'blur' }],
key: [{ required: true, message: '请输入或上传文件', trigger: 'blur' }],
description: [{ max: 200, message: '最多可输入200个字符' }],
};
const headers = {
authorization: 'authorization-text',
const onFinish = async (values: any) => {
values.configs = {
cert: formData.cert,
key: formData.key,
};
delete values.cert;
delete values.key;
const response = await save(values)
if (response.status === 200) {
message.success('操作成功')
}
};
const handleChange = (info: any) => {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}
const changeFileValue = (v: any) => {
formData[v.name] = v.data;
};
const handleChange = (info: UploadChangeParam) => {
loading.value = true;
if (info.file.status === 'done') {
message.success(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} file upload failed.`);
message.success('上传成功!');
const result = info.file.response?.result;
formData.cert = result;
loading.value = false;
}
};
const fileList = ref([]);
</script>
<style lang="less" scoped>

View File

@ -0,0 +1,71 @@
<template>
<a-tree
:tree-data="treeData"
@select="clickSelectItem"
showLine
class="left-tree-container"
>
<template #title="{ name }">
{{ name }}
</template>
</a-tree>
</template>
<script setup lang="ts">
import { TreeProps } from 'ant-design-vue';
import { getTreeOne_api, getTreeTwo_api } from '@/api/system/apiPage';
type treeNodeTpye = {
name: string;
url: string;
children?: treeNodeTpye[];
};
const emits = defineEmits(['select']);
const treeData: TreeProps['treeData'] = ref([]);
const getTreeData = () => {
let tree: treeNodeTpye[] = [];
getTreeOne_api().then((resp) => {
tree = resp.urls.map((item) => ({
...item,
key: item.url,
}));
const allPromise = tree.map((item) => getTreeTwo_api(item.name));
Promise.all(allPromise).then((values) => {
values.forEach((item, i) => {
tree[i].children = combData(item.paths);
});
console.log(tree);
treeData.value = tree
});
});
};
const clickSelectItem = (key, { node }) => {
emits('select', node);
};
onMounted(() => {
getTreeData();
});
const combData = (dataSource: object): object[] => {
const apiList: object[] = [];
const keys = Object.keys(dataSource);
keys.forEach((key) => {
const method = Object.keys(dataSource[key] || {})[0];
const name = dataSource[key][method].tags[0];
let apiObj = apiList.find((item) => item.name === name);
if (!apiObj) {
apiObj = { name, link: key, methods: dataSource[key], key };
apiList.push(apiObj);
}
});
return apiList;
};
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,15 @@
<template>
<a-card class="api-page-container" >
<LeftTree />
</a-card>
</template>
<script setup lang="ts">
import LeftTree from './components/LeftTree.vue';
</script>
<style scoped>
.api-page-container {
height: 100%;
}
</style>

View File

@ -1,44 +0,0 @@
<template>
<div class="box">
<JTable
:columns="[
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
}
]"
>
<template #headerTitle>
<a-button type="primary">新增</a-button>
</template>
<template #cardRender="slotProps">
{{slotProps.name}}
</template>
</JTable>
</div>
</template>
<script setup lang="ts">
import { post } from "@/utils/request";
// :request="post('/device-product/_query', {})"
</script>
<style lang="less" scoped>
.box {
padding: 20px;
background: #f0f2f5;
}
</style>

View File

@ -18,8 +18,9 @@
"paths": {
"@/*": ["./src/*"]
},
"types": ["ant-design-vue/typings/global"]
"types": ["ant-design-vue/typings/global"],
"suppressImplicitAnyIndexErrors": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
"references": [{ "path": "./tsconfig.node.json" }],
}

View File

@ -34,6 +34,14 @@
"@jridgewell/gen-mapping" "^0.1.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@ampproject/remapping@^2.1.0":
version "2.2.0"
resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==
dependencies:
"@jridgewell/gen-mapping" "^0.1.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@ant-design/colors@^6.0.0":
version "6.0.0"
resolved "https://registry.npmmirror.com/@ant-design/colors/-/colors-6.0.0.tgz"
@ -287,6 +295,29 @@
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/plugin-syntax-typescript" "^7.20.0"
"@babel/plugin-syntax-jsx@^7.0.0":
version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0"
integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==
dependencies:
"@babel/helper-plugin-utils" "^7.18.6"
"@babel/plugin-syntax-typescript@^7.20.0":
version "7.20.0"
resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz#4e9a0cfc769c85689b77a2e642d24e9f697fc8c7"
integrity sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==
dependencies:
"@babel/helper-plugin-utils" "^7.19.0"
"@babel/plugin-transform-typescript@^7.20.2":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.7.tgz#673f49499cd810ae32a1ea5f3f8fab370987e055"
integrity sha512-m3wVKEvf6SoszD8pu4NZz3PvfKRCMgk6D6d0Qi9hNnlM5M6CFS92EgF4EiHVLKbU0r/r7ty1hg7NPZwE7WRbYw==
dependencies:
"@babel/helper-create-class-features-plugin" "^7.20.7"
"@babel/helper-plugin-utils" "^7.20.2"
"@babel/plugin-syntax-typescript" "^7.20.0"
"@babel/runtime@^7.10.5":
version "7.20.7"
resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.20.7.tgz"
@ -496,6 +527,40 @@
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
"@babel/template@^7.0.0", "@babel/template@^7.18.10", "@babel/template@^7.20.7":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8"
integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==
dependencies:
"@babel/code-frame" "^7.18.6"
"@babel/parser" "^7.20.7"
"@babel/types" "^7.20.7"
"@babel/traverse@^7.0.0", "@babel/traverse@^7.20.10", "@babel/traverse@^7.20.12", "@babel/traverse@^7.20.7":
version "7.20.12"
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz#7f0f787b3a67ca4475adef1f56cb94f6abd4a4b5"
integrity sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==
dependencies:
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.20.7"
"@babel/helper-environment-visitor" "^7.18.9"
"@babel/helper-function-name" "^7.19.0"
"@babel/helper-hoist-variables" "^7.18.6"
"@babel/helper-split-export-declaration" "^7.18.6"
"@babel/parser" "^7.20.7"
"@babel/types" "^7.20.7"
debug "^4.1.0"
globals "^11.1.0"
"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.7":
version "7.20.7"
resolved "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f"
integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==
dependencies:
"@babel/helper-string-parser" "^7.19.4"
"@babel/helper-validator-identifier" "^7.19.1"
to-fast-properties "^2.0.0"
"@ctrl/tinycolor@^3.4.0":
version "3.5.0"
resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.5.0.tgz"
@ -815,6 +880,15 @@
"@babel/plugin-transform-typescript" "^7.20.2"
"@vue/babel-plugin-jsx" "^1.1.1"
"@vitejs/plugin-vue-jsx@^3.0.0":
version "3.0.0"
resolved "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-3.0.0.tgz#42e89d6d9eb89604d109ff9a615d77c3c080dd25"
integrity sha512-vurkuzgac5SYuxd2HUZqAFAWGTF10diKBwJNbCvnWijNZfXd+7jMtqjPFbGt7idOJUn584fP1Ar9j/GN2jQ3Ew==
dependencies:
"@babel/core" "^7.20.5"
"@babel/plugin-transform-typescript" "^7.20.2"
"@vue/babel-plugin-jsx" "^1.1.1"
"@vitejs/plugin-vue@^4.0.0":
version "4.0.0"
resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-4.0.0.tgz"