Merge branch 'dev' into dev-hub

This commit is contained in:
jackhoo_98 2023-03-21 18:07:11 +08:00
commit d5b0a2b4d8
61 changed files with 443 additions and 260 deletions

View File

@ -20,13 +20,15 @@ import { CSSProperties, PropType } from 'vue';
import AMap, { initAMapApiLoader } from '@vuemap/vue-amap';
import '@vuemap/vue-amap/dist/style.css';
import { getAMapUiPromise } from './utils';
import { useSystem } from '@/store/system';
const system = useSystem();
interface AMapProps {
style?: CSSProperties;
class?: string;
AMapUI?: string | boolean;
}
const amapKey = localStorage.getItem('amap_key')
const amapKey = system.$state.configInfo.amap?.apiKey;
initAMapApiLoader({
key: amapKey || '',

View File

@ -36,6 +36,7 @@ import DefaultSetting from '../../../config/config';
import { useMenuStore } from '@/store/menu';
import { clearMenuItem } from 'jetlinks-ui-components/es/ProLayout/util';
import { AccountMenu } from '@/router/menu'
import { useSystem } from '@/store/system';
type StateType = {
collapsed: boolean;
@ -49,11 +50,14 @@ const route = useRoute();
const menu = useMenuStore();
const system = useSystem();
const configInfo = system.configInfo;
const layoutConf = reactive({
theme: DefaultSetting.layout.theme,
theme: configInfo.front?.headerTheme || DefaultSetting.layout.theme,
siderWidth: DefaultSetting.layout.siderWidth,
logo: DefaultSetting.layout.logo,
title: DefaultSetting.layout.title,
logo: configInfo.front?.logo || DefaultSetting.layout.logo,
title: configInfo.front?.title || DefaultSetting.layout.title,
menuData: [...clearMenuItem(menu.siderMenus), AccountMenu],
// menuData: menu.siderMenus,
splitMenus: true,

View File

@ -1,6 +1,6 @@
import { ProductItem } from "@/views/device/Product/typings";
import { defineStore } from "pinia";
import { detail , getDeviceNumber} from '@/api/device/product'
import { detail, getDeviceNumber } from '@/api/device/product'
import encodeQuery from "@/utils/encodeQuery";
export const useProductStore = defineStore({
@ -17,22 +17,24 @@ export const useProductStore = defineStore({
},
async getDetail(id: string) {
const resp = await detail(id)
if(resp.status === 200){
this.current = resp.result
if (resp.status === 200) {
this.current = {
...this.current,...resp.result
}
this.detail = resp.result
}
},
async refresh(id: string) {
this.getDetail(id)
const res = await getDeviceNumber(encodeQuery({ terms: { productId: id } }))
if(res.status === 200){
if (res.status === 200) {
this.current.count = res.result
}
},
setTabActiveKey(key: string) {
this.tabActiveKey = key
},
reSet(){
reSet() {
this.current = {} as ProductItem
this.detail = {} as ProductItem
}

View File

@ -7,4 +7,13 @@ export const phoneRegEx = (value: string) => {
const phone = new RegExp('^(((\\+86)|(\\+86-))|((86)|(86\\-))|((0086)|(0086\\-)))?1[3|5|7|8|9]\\d{9}$')
const mobile = /(0[0-9]{2,3})([2-9][0-9]{6,7})+([0-9]{8,11})?$/
return phone.test(value) || mobile.test(value)
}
/**
*
* @param value
* @returns {boolean}
*/
export const passwordRegEx = (value: string) => {
const password = new RegExp(/^\S*(?=\S{8,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])\S*$/)
return password.test(value)
}

View File

@ -12,6 +12,7 @@
:request="queryTree"
model="TABLE"
type="TREE"
v-model:expandedRowKeys="expandedRowKeys"
:scroll="{ y: 550 }"
:defaultParams="{
paging: false,
@ -128,6 +129,7 @@ let params = ref();
*/
const handleSearch = (e: any) => {
params.value = e;
expandedRowKeys.value = []
};
/**
* 操作栏按钮

View File

@ -28,7 +28,7 @@
</template>
<script setup lang="ts">
import moment from 'moment';
import dayjs from 'dayjs';
import { PropType } from 'vue';
interface BtnOptions {
@ -70,8 +70,8 @@ const rangeVal = ref<[string, string]>();
const rangeChange = (val: any) => {
radioValue.value = undefined;
emit('change', {
start: moment(val[0]).valueOf(),
end: moment(val[1]).valueOf(),
start: dayjs(val[0]).valueOf(),
end: dayjs(val[1]).valueOf(),
type: undefined,
});
};
@ -79,29 +79,29 @@ const rangeChange = (val: any) => {
const getTimeByType = (type: string) => {
switch (type) {
case 'hour':
return moment().subtract(1, 'hours').valueOf();
return dayjs().subtract(1, 'hours').valueOf();
case 'week':
return moment().subtract(6, 'days').valueOf();
return dayjs().subtract(6, 'days').valueOf();
case 'month':
return moment().subtract(29, 'days').valueOf();
return dayjs().subtract(29, 'days').valueOf();
case 'year':
return moment().subtract(365, 'days').valueOf();
return dayjs().subtract(365, 'days').valueOf();
default:
return moment().startOf('day').valueOf();
return dayjs().startOf('day').valueOf();
}
};
const handleBtnChange = (val: string) => {
radioValue.value = val;
let endTime = moment(new Date()).valueOf();
let endTime = dayjs(new Date()).valueOf();
let startTime = getTimeByType(val);
if (val === 'yesterday') {
startTime = moment().subtract(1, 'days').startOf('day').valueOf();
endTime = moment().subtract(1, 'days').endOf('day').valueOf();
startTime = dayjs().subtract(1, 'days').startOf('day').valueOf();
endTime = dayjs().subtract(1, 'days').endOf('day').valueOf();
}
rangeVal.value = [
moment(startTime).format('YYYY-MM-DD HH:mm:ss'),
moment(endTime).format('YYYY-MM-DD HH:mm:ss'),
dayjs(startTime).format('YYYY-MM-DD HH:mm:ss'),
dayjs(endTime).format('YYYY-MM-DD HH:mm:ss'),
];
emit('change', {
start: startTime,
@ -110,8 +110,5 @@ const handleBtnChange = (val: string) => {
});
};
handleBtnChange(radioValue.value);
watch(
() => radioValue.value,
{ deep: true, immediate: true },
);
watch(() => radioValue.value, { deep: true, immediate: true });
</script>

View File

@ -58,7 +58,7 @@
<j-col :span="24">
<div class="device-position">
<Guide title="设备分布"></Guide>
<div class="device-map" >
<div class="device-map">
<Amap></Amap>
</div>
</div>
@ -83,7 +83,9 @@ import type { Footer } from '@/views/device/DashBoard/typings';
import TopCard from '@/views/device/DashBoard/components/TopCard.vue';
import { useMenuStore } from '@/store/menu';
import Amap from './components/Amap.vue';
let AmapKey = localStorage.getItem('amap_key');
import { useSystem } from '@/store/system';
const system = useSystem();
const AmapKey = system.$state.configInfo.amap?.apiKey;
let productTotal = ref(0);
let productFooter = ref<Footer[]>([
{
@ -257,10 +259,30 @@ const setOnlineChartOpition = (x: Array<any>, y: Array<number>): void => {
{
name: '在线数',
data: y,
type: 'bar',
type: 'line',
smooth: true, // 线
symbolSize: 0, //
showBackground: true,
itemStyle: {
color: '#D3ADF7',
color: '#D3ADF7',
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: '#D3ADF7', // 100%
},
{
offset: 1,
color: '#FFFFFF', // 0%
},
],
global: false, // false
},
},
},
],
@ -346,35 +368,35 @@ const setDevMesChartOption = (
right: '50px',
},
series: [
{
name: '消息量',
data: y,
type: 'bar',
// type: 'line',
// smooth: true,
color: '#597EF7',
barWidth: '30%',
// areaStyle: {
// color: {
// type: 'linear',
// x: 0,
// y: 0,
// x2: 0,
// y2: 1,
// colorStops: [
// {
// offset: 0,
// color: '#685DEB', // 100%
// },
// {
// offset: 1,
// color: '#FFFFFF', // 0%
// },
// ],
// global: false, // false
// },
// },
},
// {
// name: '',
// data: y,
// type: 'bar',
// // type: 'line',
// // smooth: true,
// color: '#597EF7',
// barWidth: '30%',
// // areaStyle: {
// // color: {
// // type: 'linear',
// // x: 0,
// // y: 0,
// // x2: 0,
// // y2: 1,
// // colorStops: [
// // {
// // offset: 0,
// // color: '#685DEB', // 100%
// // },
// // {
// // offset: 1,
// // color: '#FFFFFF', // 0%
// // },
// // ],
// // global: false, // false
// // },
// // },
// },
{
name: '占比',
data: y,
@ -383,6 +405,26 @@ const setDevMesChartOption = (
smooth: true,
symbolSize: 0, //
color: '#96ECE3',
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: '#96ECE3', // 100%
},
{
offset: 1,
color: '#FFFFFF', // 0%
},
],
global: false, // false
},
},
},
],
};

View File

@ -45,7 +45,7 @@
<script setup lang="ts">
import { ComponentInternalInstance } from 'vue';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { useInstanceStore } from '@/store/instance';
import { execute } from '@/api/device/instance';

View File

@ -118,7 +118,7 @@
<script setup lang="ts">
import { ComponentInternalInstance } from 'vue';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { useInstanceStore } from '@/store/instance';
import { execute } from '@/api/device/instance';

View File

@ -29,12 +29,12 @@
}}</j-button>
</j-descriptions-item>
<j-descriptions-item label="创建时间">{{
moment(productStore.current.createTime).format(
dayjs(productStore.current.createTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}</j-descriptions-item>
<j-descriptions-item label="更新时间">{{
moment(productStore.current.modifyTime).format(
dayjs(productStore.current.modifyTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}</j-descriptions-item>
@ -51,7 +51,7 @@
<script lang="ts" setup>
import { useProductStore } from '@/store/product';
import Save from '../../Save/index.vue';
import moment from 'moment';
import dayjs from 'dayjs';
import { useRoute } from 'vue-router';
const productStore = useProductStore();
const route = useRoute();

View File

@ -398,6 +398,7 @@ import 'driver.js/dist/driver.min.css';
import { marked } from 'marked';
import type { TableColumnType } from 'ant-design-vue';
import { useMenuStore } from '@/store/menu';
import _ from 'lodash';
const formRef = ref();
const menuStore = useMenuStore();
const permissionStore = usePermissionStore();
@ -907,11 +908,11 @@ const submitData = async () => {
productStore.current = { ...res.result };
access.value = res.result;
message.success('操作成功!');
getData(obj.accessId);
}
visible.value = false;
queryParams.value = {};
});
getData(obj.accessId);
}
} else {
message.error('请选择接入方式');
@ -954,6 +955,17 @@ const getData = async (accessId?: string) => {
metadata.value = (resp?.result[0] as ConfigMetadata) || {
properties: [],
};
// udp
if (metadata.value?.properties) {
metadata.value?.properties.forEach((item) => {
if (
item.name === '流传输模式' && (!productStore.current?.configuration || !productStore.current?.configuration.hasOwnProperty(item.name))
) {
formData.data[item.name] =
item.type.expands?.defaultValue;
}
});
}
if (accessId) {
//
getGuide(resp?.result.length); //

View File

@ -163,6 +163,7 @@ watch(
productStore.reSet();
productStore.tabActiveKey = 'Info';
productStore.refresh(newId as string);
console.log(productStore);
}
},
{ immediate: true, deep: true },

View File

@ -46,6 +46,7 @@
v-bind="slotProps"
:active="_selectedRowKeys.includes(slotProps.id)"
:status="slotProps.state"
@click="handleView(slotProps.id)"
:statusText="slotProps.state === 1 ? '正常' : '禁用'"
:statusNames="{
1: 'processing',
@ -66,7 +67,6 @@
<template #content>
<Ellipsis style="width: calc(100% - 100px)"
><span
@click.stop="handleView(slotProps.id)"
style="font-weight: 600; font-size: 16px"
>
{{ slotProps.name }}

View File

@ -338,7 +338,7 @@ const saveBasicInfo = () =>{
{
scope: 'amap',
properties: {
api: form.value.apikey,
apiKey: form.value.apikey,
},
},
{

View File

@ -67,7 +67,7 @@
<script setup lang="ts">
import CascadeApi from '@/api/media/cascade';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { PropType } from 'vue';
const route = useRoute();

View File

@ -153,7 +153,7 @@
<script setup lang="ts">
import CascadeApi from '@/api/media/cascade';
import type { ActionsType } from '@/views/device/Instance/typings';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import BindChannel from './BindChannel/index.vue';
const route = useRoute();

View File

@ -559,7 +559,7 @@
<script setup lang="ts">
import { getImage } from '@/utils/comm';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import CascadeApi from '@/api/media/cascade';
const router = useRouter();

View File

@ -146,7 +146,7 @@
<script setup lang="ts">
import CascadeApi from '@/api/media/cascade';
import type { ActionsType } from '@/views/device/Instance/typings';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { getImage } from '@/utils/comm';
import Publish from './Publish/index.vue';

View File

@ -167,7 +167,7 @@
<script setup lang="ts">
import ChannelApi from '@/api/media/channel';
import { PropType } from 'vue';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import type { Rule } from 'ant-design-vue/es/form';
const route = useRoute();

View File

@ -118,7 +118,7 @@
import ChannelApi from '@/api/media/channel';
import type { ActionsType } from '@/views/device/Instance/typings';
import { useMenuStore } from 'store/menu';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import Save from './Save.vue';
import Live from './Live/index.vue';
import Tree from './Tree/index.vue';

View File

@ -8,7 +8,7 @@
<script setup lang="ts">
import type { recordsItemType } from './typings';
import playBackApi from '@/api/media/playback';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
interface Props {
type: string;

View File

@ -33,7 +33,7 @@
</template>
<script setup lang="ts">
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import type { recordsItemType } from './typings';
import type { Dayjs } from 'dayjs';
import dayjs from 'dayjs';

View File

@ -151,7 +151,7 @@
</template>
<script setup lang="ts">
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import DeviceApi from '@/api/media/device';
import { getImage } from '@/utils/comm';
import { gatewayType } from '@/views/media/Device/typings';

View File

@ -297,7 +297,7 @@
<script setup lang="ts">
import { getImage } from '@/utils/comm';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import DeviceApi from '@/api/media/device';
import { PROVIDER_OPTIONS } from '@/views/media/Device/const';
import type { ProductType } from '@/views/media/Device/typings';
@ -362,6 +362,7 @@ const saveProductVis = ref(false);
* 获取详情
*/
const getDetail = async () => {
if (!route.query.id) return;
const res = await DeviceApi.detail(route.query.id as string);
Object.assign(formData.value, res.result);
formData.value.channel = res.result.provider;

View File

@ -153,7 +153,7 @@
<script setup lang="ts">
import DeviceApi from '@/api/media/device';
import type { ActionsType } from '@/views/device/Instance/typings';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { getImage } from '@/utils/comm';
import { PROVIDER_OPTIONS } from '@/views/media/Device/const';
import { providerType } from './const';

View File

@ -93,7 +93,7 @@ import { usePermissionStore } from '@/store/permission';
import type { bootConfig, recommendList } from '@/views/home/typing';
import deviceApi from '@/api/media/device';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { useMenuStore } from 'store/menu';

View File

@ -52,34 +52,50 @@
<template v-else>
<j-form-item
:name="['templateDetailTable', index, 'value']"
:rules="{
required: record.required,
message: '该字段为必填字段',
}"
:rules="[
{
required: record.required,
message: '该字段为必填字段',
},
...record.otherRules,
]"
>
<ToUser
v-if="record.type === 'user'"
v-model:toUser="record.value"
:type="data.type"
:config-id="data.id"
/>
<ToOrg
v-else-if="record.type === 'org'"
:type="data.type"
:config-id="data.id"
v-model:toParty="record.value"
/>
<ToTag
v-else-if="record.type === 'tag'"
:type="data.type"
:config-id="data.id"
v-model:toTag="record.value"
/>
<ValueItem
v-else
v-model:modelValue="record.value"
:itemType="record.type"
/>
<template
v-if="
data.type === 'dingTalk' ||
data.type === 'weixin'
"
>
<ToUser
v-if="record.type === 'user'"
v-model:toUser="record.value"
:type="data.type"
:config-id="data.id"
/>
<ToOrg
v-else-if="record.type === 'org'"
:type="data.type"
:config-id="data.id"
v-model:toParty="record.value"
/>
<ToTag
v-else-if="record.type === 'tag'"
:type="data.type"
:config-id="data.id"
v-model:toTag="record.value"
/>
<ValueItem
v-else
v-model:modelValue="record.value"
:itemType="record.type"
/>
</template>
<template v-else>
<ValueItem
v-model:modelValue="record.value"
:itemType="record.type"
/>
</template>
</j-form-item>
</template>
</template>
@ -96,11 +112,13 @@ import type {
TemplateFormData,
IVariableDefinitions,
} from '@/views/notice/Template/types';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import ToUser from '@/views/notice/Template/Detail/components/ToUser.vue';
import ToOrg from '@/views/notice/Template/Detail/components/ToOrg.vue';
import ToTag from '@/views/notice/Template/Detail/components/ToTag.vue';
import type { Rule } from 'ant-design-vue/es/form';
import { phoneRegEx } from '@/utils/validate';
type Emits = {
(e: 'update:visible', data: boolean): void;
@ -134,7 +152,7 @@ const getTemplateList = async () => {
const { result } = await ConfigApi.getTemplate(params, props.data.id);
templateList.value = result;
formData.value.templateId = result[0]?.id as string;
getTemplateDetail()
getTemplateDetail();
};
watch(
@ -155,7 +173,27 @@ const getTemplateDetail = async () => {
(m: any) => ({
...m,
type: m.expands ? m.expands.businessType : m.type,
value: undefined,
value: undefined,
//
otherRules:
m.id === 'calledNumber' || m.id === 'phoneNumber'
? [
{
max: 64,
message: '最多可输入64个字符',
trigger: 'change',
},
{
trigger: 'change',
validator(_rule: Rule, value: string) {
if (!value) return Promise.resolve();
if (!phoneRegEx(value))
return Promise.reject('请输入有效号码');
return Promise.resolve();
},
},
]
: [],
}),
);
};

View File

@ -323,7 +323,7 @@
<script setup lang="ts">
import { getImage } from '@/utils/comm';
import { Form } from 'ant-design-vue';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import type { ConfigFormData } from '../types';
import {
NOTICE_METHOD,

View File

@ -135,7 +135,7 @@
<script setup lang="ts" name="SyncUser">
import configApi from '@/api/notice/config';
import { PropType } from 'vue';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import type { ActionsType } from '@/views/device/Instance/typings';
import { Form } from 'ant-design-vue';
@ -209,6 +209,7 @@ watch(
const onTreeSelect = (keys: any) => {
deptId.value = keys[0];
pageSize.value = 5;
current.value = 1;
};
//

View File

@ -196,7 +196,7 @@
import ConfigApi from '@/api/notice/config';
import type { ActionsType } from '@/components/Table/index.vue';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { NOTICE_METHOD, MSG_TYPE } from '@/views/notice/const';
import SyncUser from './SyncUser/index.vue';

View File

@ -112,7 +112,7 @@ import type {
IVariableDefinitions,
BindConfig,
} from '@/views/notice/Template/types';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import ToUser from '../Detail/components/ToUser.vue';
import ToOrg from '../Detail/components/ToOrg.vue';
@ -194,7 +194,7 @@ const getTemplateDetail = async () => {
},
},
]
: '',
: [],
}),
);
};

View File

@ -760,7 +760,7 @@
<script setup lang="ts">
import { getImage } from '@/utils/comm';
import { Form, UploadChangeParam } from 'ant-design-vue';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import type { IVariableDefinitions, TemplateFormData } from '../types';
import {
NOTICE_METHOD,

View File

@ -157,7 +157,7 @@
<script setup lang="ts">
import TemplateApi from '@/api/notice/template';
import type { ActionsType } from '@/views/device/Instance/typings';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { NOTICE_METHOD, MSG_TYPE } from '@/views/notice/const';
import Debug from './Debug/index.vue';
import Log from './Log/index.vue';

View File

@ -16,7 +16,7 @@
}"
>
<template #alarmTime="slotProps">{{
moment(slotProps.alarmTime).format('YYYY-MM-DD HH:mm:ss')
dayjs(slotProps.alarmTime).format('YYYY-MM-DD HH:mm:ss')
}}</template>
<template #action="slotProps">
<j-space
@ -47,7 +47,7 @@
<script lang="ts" setup>
import { detail, queryHistoryList } from '@/api/rule-engine/log';
import { useRoute } from 'vue-router';
import moment from 'moment';
import dayjs from 'dayjs';
import type { ActionsType } from '@/components/Table/index.vue';
import { message } from 'jetlinks-ui-components';
import { useAlarmStore } from '@/store/alarm';

View File

@ -7,7 +7,7 @@
props.data?.alarmConfigName
}}</j-descriptions-item>
<j-descriptions-item label="告警时间" :span="1">{{
moment(data?.alarmTime).format('YYYY-MM-DD HH:mm:ss')
dayjs(data?.alarmTime).format('YYYY-MM-DD HH:mm:ss')
}}</j-descriptions-item>
<j-descriptions-item label="告警级别" :span="1">
<j-tooltip
@ -44,7 +44,7 @@
</template>
<script lang="ts" setup>
import moment from 'moment';
import dayjs from 'dayjs';
import { Store } from 'jetlinks-store';
import JsonViewer from 'vue-json-viewer';
const props = defineProps({

View File

@ -29,7 +29,7 @@
<template #handleTime="slotsProps">
<span>
{{
moment(slotsProps.handleTime).format(
dayjs(slotsProps.handleTime).format(
'YYYY-MM-DD HH:mm:ss'
)
}}
@ -41,7 +41,7 @@
<template #alarmTime="slotProps">
<span>
{{
moment(slotProps.alarmTime).format(
dayjs(slotProps.alarmTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}
@ -53,7 +53,7 @@
<script lang="ts" setup>
import { queryHandleHistory } from '@/api/rule-engine/log';
import moment from 'moment';
import dayjs from 'dayjs';
const props = defineProps({
data: {
type: Object,

View File

@ -79,7 +79,7 @@
<Ellipsis
><div>
{{
moment(slotProps?.alarmTime).format(
dayjs(slotProps?.alarmTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}
@ -157,7 +157,7 @@ import Search from '@/components/Search';
import { useAlarmStore } from '@/store/alarm';
import { storeToRefs } from 'pinia';
import { Store } from 'jetlinks-store';
import moment from 'moment';
import dayjs from 'dayjs';
import type { ActionsType } from '@/components/Table';
import SolveComponent from '../SolveComponent/index.vue';
import SolveLog from '../SolveLog/index.vue';

View File

@ -10,7 +10,7 @@
:src="getImage('/alarm/bashboard.png')"
alt=""
/>{{
moment(item.alarmTime).format(
dayjs(item.alarmTime).format(
'YYYY-MM-DD HH:mm:ss',
)
}}
@ -64,7 +64,7 @@
import { Empty } from 'jetlinks-ui-components';
import { getImage } from '@/utils/comm';
import { useMenuStore } from '@/store/menu';
import moment from 'moment';
import dayjs from 'dayjs';
const props = defineProps({
alarmList: {
type: Array,

View File

@ -28,7 +28,7 @@
</template>
<script setup lang="ts">
import moment from 'moment';
import dayjs from 'dayjs';
import { PropType } from 'vue';
interface BtnOptions {
@ -70,8 +70,8 @@ const rangeVal = ref<[string, string]>();
const rangeChange = (val: any) => {
radioValue.value = undefined;
emit('change', {
start: moment(val[0]).valueOf(),
end: moment(val[1]).valueOf(),
start: dayjs(val[0]).valueOf(),
end: dayjs(val[1]).valueOf(),
type: undefined,
});
};
@ -79,29 +79,29 @@ const rangeChange = (val: any) => {
const getTimeByType = (type: string) => {
switch (type) {
case 'hour':
return moment().subtract(1, 'hours').valueOf();
return dayjs().subtract(1, 'hours').valueOf();
case 'week':
return moment().subtract(6, 'days').valueOf();
return dayjs().subtract(6, 'days').valueOf();
case 'month':
return moment().subtract(29, 'days').valueOf();
return dayjs().subtract(29, 'days').valueOf();
case 'year':
return moment().subtract(365, 'days').valueOf();
return dayjs().subtract(365, 'days').valueOf();
default:
return moment().startOf('day').valueOf();
return dayjs().startOf('day').valueOf();
}
};
const handleBtnChange = (val: string) => {
radioValue.value = val;
let endTime = moment(new Date()).valueOf();
let endTime = dayjs(new Date()).valueOf();
let startTime = getTimeByType(val);
if (val === 'yesterday') {
startTime = moment().subtract(1, 'days').startOf('day').valueOf();
endTime = moment().subtract(1, 'days').endOf('day').valueOf();
startTime = dayjs().subtract(1, 'days').startOf('day').valueOf();
endTime = dayjs().subtract(1, 'days').endOf('day').valueOf();
}
rangeVal.value = [
moment(startTime).format('YYYY-MM-DD HH:mm:ss'),
moment(endTime).format('YYYY-MM-DD HH:mm:ss'),
dayjs(startTime).format('YYYY-MM-DD HH:mm:ss'),
dayjs(endTime).format('YYYY-MM-DD HH:mm:ss'),
];
emit('change', {
start: startTime,

View File

@ -55,15 +55,38 @@
</div>
<div class="alarmRank">
<h4>告警排名</h4>
<ul v-if="state.ranking.length" class="rankingList">
<li v-for="(item,i) in state.ranking" :key="item.targetId">
<img :src="getImage(`/rule-engine/dashboard/ranking/${i+1}.png`)" alt="">
<span class="rankingItemTitle" :title="item.targetName">{{item.targetName}}</span>
<span class="rankingItemValue">{{item.count}}</span>
<ul
v-if="state.ranking.length"
class="rankingList"
>
<li
v-for="(item, i) in state.ranking"
:key="item.targetId"
>
<img
:src="
getImage(
`/rule-engine/dashboard/ranking/${
i + 1
}.png`,
)
"
alt=""
/>
<span
class="rankingItemTitle"
:title="item.targetName"
>{{ item.targetName }}</span
>
<span class="rankingItemValue">{{
item.count
}}</span>
</li>
</ul>
<div v-else class="empty-body">
<j-empty :image="Empty.PRESENTED_IMAGE_SIMPLE"></j-empty>
<j-empty
:image="Empty.PRESENTED_IMAGE_SIMPLE"
></j-empty>
</div>
</div>
</div>
@ -92,7 +115,7 @@ import {
getAlarmConfigCount,
getAlarmLevel,
} from '@/api/rule-engine/dashboard';
import moment from 'moment';
import dayjs from 'dayjs';
let currentMonAlarm = ref<Footer[]>([
{
title: '当月告警',
@ -169,7 +192,7 @@ const today = {
time: '1d',
// targetType: 'device',
format: 'HH:mm:ss',
from: moment(new Date(new Date().setHours(0, 0, 0, 0))).format(
from: dayjs(new Date(new Date().setHours(0, 0, 0, 0))).format(
'YYYY-MM-DD HH:mm:ss',
),
to: 'now',
@ -246,9 +269,28 @@ const getDashBoard = () => {
{
name: '告警数',
data: fifteenData.map((item) => item.value),
type: 'bar',
itemStyle: {
color: '#2F54EB',
type: 'line',
color: '#2F54EB',
symbolSize: 0,
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 0,
colorStops: [
{
offset: 0,
color: '#2F54EB', // 100%
},
{
offset: 1,
color: '#FFFFFF', // 0%
},
],
global: false, // false
},
},
},
],
@ -353,8 +395,8 @@ const selectChange = () => {
// to: 'now',
limit: limit, // 12
// time: params.time.type === 'today' ? '1h' : '1d',
from: moment(queryCodition.startTime).format('YYYY-MM-DD HH:mm:ss'),
to: moment(queryCodition.endTime).format('YYYY-MM-DD HH:mm:ss'),
from: dayjs(queryCodition.startTime).format('YYYY-MM-DD HH:mm:ss'),
to: dayjs(queryCodition.endTime).format('YYYY-MM-DD HH:mm:ss'),
// limit: 30,
},
};
@ -370,8 +412,8 @@ const selectChange = () => {
// time: '1h',
time: time,
targetType: queryCodition.targetType,
from: moment(queryCodition.startTime).format('YYYY-MM-DD HH:mm:ss'),
to: moment(queryCodition.endTime).format('YYYY-MM-DD HH:mm:ss'),
from: dayjs(queryCodition.startTime).format('YYYY-MM-DD HH:mm:ss'),
to: dayjs(queryCodition.endTime).format('YYYY-MM-DD HH:mm:ss'),
limit: 9,
},
};
@ -536,12 +578,12 @@ const selectChange = () => {
}
}
.empty-body {
height: 490px;
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
width: 100%;
// height: 100%;
height: 490px;
display: flex;
flex-direction: column;
align-content: center;
justify-content: center;
width: 100%;
// height: 100%;
}
</style>

View File

@ -51,7 +51,7 @@ import {
} from '@/api/system/apply';
import { CheckInfo } from 'ant-design-vue/lib/vc-tree/props';
import { useMenuStore } from '@/store/menu';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { getMenuTree_api } from '@/api/system/menu';
const menuStory = useMenuStore();

View File

@ -187,7 +187,7 @@ import {
import { ActionsType } from '@/components/Table';
import { getImage } from '@/utils/comm';
import { useMenuStore } from '@/store/menu';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const menuStory = useMenuStore();
const permission = 'system/Apply';

View File

@ -286,7 +286,7 @@
<script setup lang="ts" name="Basis">
import { formType, uploaderType } from './typing';
import { getImage } from '@/utils/comm.ts';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
import { LocalStore } from '@/utils/comm';
@ -348,9 +348,10 @@ const form = reactive<formType>({
headerTheme: configInfo.front?.headerTheme,
logo: configInfo.front?.logo || '/public/logo.png',
ico: configInfo.front?.ico || '/public/favicon.ico',
backgroud: configInfo.front?.backgroud || '/public/images/login.png',
backgroud:
configInfo.front?.backgroud || '/public/images/login.png',
apiKey: configInfo.amap?.apiKey,
"base-path": configInfo.paths?.['base-path']
'base-path': configInfo.paths?.['base-path'],
};
},
clickSave: () => {
@ -398,23 +399,24 @@ const form = reactive<formType>({
const { formValue, rulesFrom } = toRefs(form);
const uploader: uploaderType = {
imageTypes: [
'image/jpg',
'image/jpeg',
'image/png',
'image/jfif',
'image/pjp',
'image/pjpeg',
],
// imageTypes: ['.jpg','.png','.jfif','.pjp','.pjpeg','.jpeg'],
// imageTypes: [
// 'image/jpg',
// 'image/jpeg',
// 'image/png',
// 'image/jfif',
// 'image/pjp',
// 'image/pjpeg',
// ],
imageTypes: ['.jpg', '.png', '.jfif', '.pjp', '.pjpeg', '.jpeg'],
iconTypes: ['image/x-icon'],
// logo
// beforeLogoUpload: ({ size, type }: File) => {
beforeLogoUpload: (file: File) => {
console.log('file: ', file);
const typeBool =
uploader.imageTypes.filter((typeStr) => file.type.includes(typeStr))
.length > 0;
uploader.imageTypes
.map((m: string) => m.split('.')[1])
.filter((typeStr) => file.type.includes(typeStr)).length > 0;
const sizeBool = file.size / 1024 / 1024 < 4;
if (!typeBool) {
message.error(`请上传.jpg.png.jfif.pjp.pjpeg.jpeg格式的图片`);

View File

@ -151,7 +151,7 @@ import {
changeStatus_api,
delDataSource_api,
} from '@/api/system/dataSource';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const permission = 'system/DataSource';

View File

@ -140,7 +140,7 @@ import {
getPermission_api,
bindDeviceOrProductList_api,
} from '@/api/system/department';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { dictType } from '../typing';
const emits = defineEmits(['confirm', 'update:visible']);

View File

@ -21,7 +21,7 @@
<script setup lang="ts">
import type { dictType, optionsType } from '../typing';
import { updatePermission_api } from '@/api/system/department';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const emits = defineEmits(['confirm', 'update:visible']);
const props = defineProps<{

View File

@ -92,7 +92,7 @@ import { debounce, cloneDeep, omit } from 'lodash-es';
import { ArrayToTree } from '@/utils/utils';
import EditDepartmentDialog from './EditDepartmentDialog.vue';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const permission = 'system/Department';

View File

@ -210,7 +210,7 @@ import {
import { intersection } from 'lodash-es';
import type { dictType, optionsType } from '../typing';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const permission = 'system/Department';

View File

@ -240,7 +240,7 @@ import {
import { intersection } from 'lodash-es';
import type { dictType } from '../typing.d.ts';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const permission = 'system/Department';

View File

@ -36,7 +36,7 @@
<script setup lang="ts">
import { bindUser_api, getBindUserList_api } from '@/api/system/department';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const emits = defineEmits(['confirm', 'update:visible']);

View File

@ -80,7 +80,7 @@
import PermissionButton from '@/components/PermissionButton/index.vue';
import AddBindUserDialog from './components/addBindUserDialog.vue';
import { getBindUserList_api, unBindUser_api } from '@/api/system/department';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const permission = 'system/Department';

View File

@ -67,7 +67,7 @@ import PermissionButton from '@/components/PermissionButton/index.vue';
import ButtonAddDialog from '../components/ButtonAddDialog.vue';
import { getMenuInfo_api, saveMenuInfo_api } from '@/api/system/menu';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const permission = 'system/Menu';
//

View File

@ -79,7 +79,7 @@
import PermissionButton from '@/components/PermissionButton/index.vue';
import { getMenuTree_api, delMenuInfo_api } from '@/api/system/menu';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import moment from 'moment';
const permission = 'system/Menu';

View File

@ -12,16 +12,7 @@
<j-form-item
name="id"
:rules="[
{
required: true,
message: '请输入标识(ID)',
trigger: 'change',
},
{
max: 64,
message: '最多可输入64个字符',
trigger: 'change',
},
{ required: true, message: '' },
{ validator: form.rules.idCheck, trigger: 'blur' },
]"
class="question-item"
@ -61,38 +52,57 @@
placeholder="请输入名称"
/>
</j-form-item>
<!-- 操作权限列表 -->
<j-table
:columns="table.columns"
:data-source="form.data.actionTableData"
:pagination="false"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'index'">
{{
`#${
(pager.current - 1) * pager.pageSize +
(index + 1)
}.`
}}
</template>
<template
v-else-if="
column.key !== 'index' && column.key !== 'act'
"
>
<j-form-item
:name="['actionTableData', index, column.key]"
:rules="[
{
required: column.key !== 'describe',
message: `请输入${column.title}`,
},
{
max: 64,
message: '最多可输入64个字符',
},
]"
>
<j-input v-model:value="record[column.key]" />
</j-form-item>
</template>
<template v-else-if="column.key === 'act'">
<j-button
class="delete-btn"
style="padding: 0"
type="link"
@click="table.clickRemove(index)"
>
<AIcon type="DeleteOutlined" />
</j-button>
</template>
</template>
</j-table>
</j-form>
<j-table
:columns="table.columns"
:data-source="actionTableData"
:pagination="false"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key === 'index'">
{{
`#${
(pager.current - 1) * pager.pageSize + (index + 1)
}.`
}}
</template>
<template
v-else-if="column.key !== 'index' && column.key !== 'act'"
>
<j-input v-model:value="record[column.key]" />
</template>
<template v-else-if="column.key === 'act'">
<j-button
class="delete-btn"
style="padding: 0"
type="link"
@click="table.clickRemove(index)"
>
<AIcon type="DeleteOutlined" />
</j-button>
</template>
</template>
</j-table>
<div class="pager" v-show="pager.total > pager.pageSize">
<j-select v-model:value="pager.current" style="width: 60px">
<j-select-option v-for="(val, i) in pageArr" :value="i + 1">{{
@ -156,6 +166,16 @@ const form = reactive({
name: '',
id: '',
...props.data,
actionTableData: computed(() => {
const startIndex = (pager.current - 1) * pager.pageSize;
const endIndex = Math.min(
pager.current * pager.pageSize,
table.data.length,
);
console.log(startIndex, endIndex);
return table.data.slice(startIndex, endIndex);
}),
},
rules: {
//
@ -216,7 +236,7 @@ const table = reactive({
key: 'act',
},
],
data: props.data.id ? props.data.actions : [...defaultAction],
data: props.data.id ? [...props.data.actions] : [...defaultAction],
clickRemove: (index: number) => {
pager.total -= 1;
table.data.splice(index, 1);
@ -245,16 +265,16 @@ const pageArr = computed(() => {
const maxPageNum = Math.ceil(pager.total / pager.pageSize);
return new Array(maxPageNum).fill(1);
});
const actionTableData = computed(() => {
const startIndex = (pager.current - 1) * pager.pageSize;
const endIndex = Math.min(
pager.current * pager.pageSize,
table.data.length,
);
console.log(startIndex, endIndex);
// const actionTableData = computed(() => {
// const startIndex = (pager.current - 1) * pager.pageSize;
// const endIndex = Math.min(
// pager.current * pager.pageSize,
// table.data.length,
// );
// console.log(startIndex, endIndex);
return table.data.slice(startIndex, endIndex);
});
// return table.data.slice(startIndex, endIndex);
// });
</script>
<style lang="less" scoped>

View File

@ -3,8 +3,8 @@
<div class="permission-container">
<pro-search
:columns="columns"
target="category"
@search="(params:any)=>queryParams = {...params}"
target="system-permission"
@search="handleSearch"
/>
<j-pro-table
@ -141,7 +141,7 @@
<script setup lang="ts">
import PermissionButton from '@/components/PermissionButton/index.vue';
import EditDialog from './components/EditDialog.vue';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import {
getPermission_api,
editPermission_api,
@ -172,27 +172,24 @@ const columns = [
ellipsis: true,
search: {
type: 'string',
first: true,
},
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
ellipsis: true,
scopedSlots: true,
search: {
type: 'select',
options: [
{
label: '启用',
value: 1,
},
{
label: '禁用',
value: 0,
},
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 },
],
handleValue: (v: any) => {
return v;
},
},
scopedSlots: true,
},
{
title: '操作',
@ -204,6 +201,9 @@ const columns = [
},
];
const queryParams = ref({});
const handleSearch = (e: any) => {
queryParams.value = e;
};
//
const tableRef = ref<Record<string, any>>({}); //
const table = {
@ -237,7 +237,7 @@ const table = {
clickExport: () => {
const params = {
paging: false,
...queryParams,
...queryParams.value,
};
exportPermission_api(params).then((resp) => {
if (resp.status === 200) {

View File

@ -71,7 +71,7 @@ import {
getRelationshipList_api,
delRelation_api,
} from '@/api/system/relationship';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import EditDialog from './components/EditDialog.vue';
const permission = 'system/Relationship';

View File

@ -65,7 +65,7 @@
import PermissionButton from '@/components/PermissionButton/index.vue';
import AddUserDialog from '../components/AddUserDialog.vue';
import { getUserByRole_api, unbindUser_api } from '@/api/system/role';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const roleId = useRoute().params.id as string;

View File

@ -35,7 +35,7 @@
<script setup lang="ts">
import { getUserByRole_api, bindUser_api } from '@/api/system/role';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const emits = defineEmits(['refresh', 'update:visible']);
const props = defineProps<{

View File

@ -70,7 +70,7 @@
import PermissionButton from '@/components/PermissionButton/index.vue';
import AddDialog from './components/AddDialog.vue';
import { getRoleList_api, delRole_api } from '@/api/system/role';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
import { useMenuStore } from '@/store/menu';
const permission = 'system/Role';

View File

@ -16,7 +16,13 @@
<j-form-item
name="name"
label="姓名"
:rules="[{ required: true, message: '请输入姓名' }]"
:rules="[
{ required: true, message: '请输入姓名' },
{
max: 64,
message: '最多可输入64个字符',
},
]"
>
<j-input
v-model:value="form.data.name"
@ -53,7 +59,7 @@
{ required: true, message: '' },
{
validator: form.rules.checkPassword,
trigger: 'blur',
trigger: 'change',
},
]"
>
@ -188,6 +194,7 @@ import {
import { Rule } from 'ant-design-vue/es/form';
import { DefaultOptionType } from 'ant-design-vue/es/vc-tree-select/TreeSelect';
import { AxiosResponse } from 'axios';
import { passwordRegEx } from '@/utils/validate';
const deptPermission = 'system/Department';
const rolePermission = 'system/Role';
@ -243,6 +250,7 @@ const form = reactive({
if (!value) return reject('请输入密码');
else if (value.length > 64) return reject('最多可输入64个字符');
else if (value.length < 8) return reject('密码不能少于8位');
else if (!passwordRegEx(value)) return reject('密码必须包含大小写英文和数字');
validateField_api('password', value).then((resp: any) => {
resp.result.passed
? resolve('')

View File

@ -122,7 +122,7 @@ import {
changeUserStatus_api,
deleteUser_api,
} from '@/api/system/user';
import { message } from 'ant-design-vue';
import { message } from 'jetlinks-ui-components';
const permission = 'system/User';