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

This commit is contained in:
XieYongHong 2023-07-14 16:52:27 +08:00
commit bf5016fca2
15 changed files with 182 additions and 112 deletions

View File

@ -20,6 +20,7 @@
<template v-for="i in list" :key="i.id"> <template v-for="i in list" :key="i.id">
<NoticeItem <NoticeItem
:data="i" :data="i"
:type="item.key"
@action="emits('action')" @action="emits('action')"
@refresh="onRefresh(item.key)" @refresh="onRefresh(item.key)"
/> />

View File

@ -55,6 +55,10 @@ const props = defineProps({
type: Object, type: Object,
default: () => {}, default: () => {},
}, },
type: {
type: String,
default: "alarm"
}
}); });
const num = ref<-100 | 0>(0); const num = ref<-100 | 0>(0);
@ -74,10 +78,14 @@ const detail = () => {
if (route.path === '/account/center') { if (route.path === '/account/center') {
userInfo.tabKey = 'StationMessage'; userInfo.tabKey = 'StationMessage';
userInfo.messageInfo = props.data; userInfo.messageInfo = props.data;
userInfo.other.tabKey = props.type;
} else { } else {
menuStory.routerPush('account/center', { menuStory.routerPush('account/center', {
row: props.data, row: props.data,
tabKey: 'StationMessage', tabKey: 'StationMessage',
other: {
tabKey: props.type
}
}); });
} }
emits('action'); emits('action');

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<j-dropdown placement="bottomRight"> <j-dropdown placement="bottomRight">
<div style="cursor: pointer;height: 100%;"> <div style="cursor: pointer;height: 100%;white-space: nowrap;overflow: hidden;text-overflow:ellipsis; max-width: 170px;" >
<j-avatar <j-avatar
:src="userInfo.userInfos?.avatar" :src="userInfo.userInfos?.avatar"
alt="" alt=""
@ -43,4 +43,5 @@ const logOut = () => {
}; };
</script> </script>
<style scoped></style> <style scoped>
</style>

View File

@ -7,7 +7,7 @@
<div class="left-content"> <div class="left-content">
<TitleComponent data="基本信息" /> <TitleComponent data="基本信息" />
<j-alert <j-alert
v-if="_error && modelRef?.id" v-if="!!_error && modelRef?.id && productPermission()"
style="margin: 10px 0" style="margin: 10px 0"
type="warning" type="warning"
> >
@ -26,14 +26,16 @@
" "
>{{ _error }}</span >{{ _error }}</span
> >
<j-popconfirm <PermissionButton
title="确认启用" :popConfirm="{
@confirm="onActiveProduct" title: '确认启用',
onConfirm: onActiveProduct,
}"
size="small"
:hasPermission="'device/Product:action'"
> >
<j-button size="small" 立即启用
>立即启用</j-button </PermissionButton>
>
</j-popconfirm>
</div> </div>
</template> </template>
</j-alert> </j-alert>
@ -275,7 +277,6 @@
v-if="modelRef.mappings.length" v-if="modelRef.mappings.length"
:activeKey="activeKey" :activeKey="activeKey"
@change="onCollChange" @change="onCollChange"
> >
<j-collapse-panel <j-collapse-panel
v-for="( v-for="(
@ -398,6 +399,9 @@
'', '',
) )
" "
@error="
onPlatError
"
/> />
</j-form-item> </j-form-item>
</j-col> </j-col>
@ -481,13 +485,16 @@ import _ from 'lodash';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import MSelect from '../../components/MSelect/index.vue'; import MSelect from '../../components/MSelect/index.vue';
import { _deploy } from '@/api/device/product'; import { _deploy } from '@/api/device/product';
import { usePermissionStore } from '@/store/permission';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const formRef = ref(); const formRef = ref();
const _error = ref<string>(''); const _errorSet = ref<Set<string>>(new Set());
const _set = new Set()
const hasPermission = usePermissionStore().hasPermission;
const productPermission = () => hasPermission(`device/Product:action`);
const modelRef = reactive({ const modelRef = reactive({
id: undefined, id: undefined,
@ -587,33 +594,34 @@ const onCollChange = (_key: string[]) => {
activeKey.value = _key; activeKey.value = _key;
}; };
const onActiveProduct = () => { const _error = computed(() => {
const arr = [..._set].map(async (i: any) => { return _errorSet.value.size ? `当前选择的部分产品为禁用状态` : ''
return await _deploy(i) })
})
Promise.all(arr).then((res) => { const onActiveProduct = async () => {
if(res.map(i => i?.status === 200).length === _set.size) { [..._errorSet.value.values()].forEach(async (i: any) => {
onlyMessage('操作成功!') const resp = await _deploy(i).catch((error) => {
_error.value = '' onlyMessage('操作失败', 'error');
});
if(resp?.status === 200) {
_errorSet.value.delete(i)
onlyMessage('操作成功!');
} }
_set.clear() });
}).catch((error) => { await getProduct();
onlyMessage('操作失败', 'error')
})
}; };
const onPlatError = (val: any) => {
const _item = productList.value.find((item) => item.id === val);
if (val && _item && !_item?.state) {
_errorSet.value.add(val)
}
};
const _validator = (_rule: any, value: string): Promise<any> => const _validator = (_rule: any, value: string): Promise<any> =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
const _item = productList.value.find((item) => item.id === value); const _item = productList.value.find((item) => item.id === value);
if (!_item) { if (!_item) {
return reject('关联产品已被删除,请重新选择'); return reject('关联产品已被删除,请重新选择');
} else {
if (!_item?.state) {
_set.add(value)
_error.value = `当前选择的部分产品为禁用状态`;
} else {
_error.value = '';
}
} }
return resolve(''); return resolve('');
}); });
@ -661,7 +669,9 @@ watch(
getAliyunProduct(_data?.accessConfig); getAliyunProduct(_data?.accessConfig);
} }
Object.assign(modelRef, _data); Object.assign(modelRef, _data);
activeKey.value = (_data?.mappings || []).map((_: any, index: number) => index) activeKey.value = (_data?.mappings || []).map(
(_: any, index: number) => index,
);
} }
}, },
{ immediate: true, deep: true }, { immediate: true, deep: true },

View File

@ -7,7 +7,7 @@
<div class="left-content"> <div class="left-content">
<TitleComponent data="基本信息" /> <TitleComponent data="基本信息" />
<j-alert <j-alert
v-if="_error && modelRef?.id" v-if="_error && modelRef?.id && productPermission()"
style="margin: 10px 0" style="margin: 10px 0"
type="warning" type="warning"
> >
@ -26,14 +26,16 @@
" "
>{{ _error }}</span >{{ _error }}</span
> >
<j-popconfirm <PermissionButton
title="确认启用" :popConfirm="{
@confirm="onActiveProduct" title: '确认启用',
onConfirm: onActiveProduct,
}"
size="small"
:hasPermission="'device/Product:action'"
> >
<j-button size="small" 立即启用
>立即启用</j-button </PermissionButton>
>
</j-popconfirm>
</div> </div>
</template> </template>
</j-alert> </j-alert>
@ -461,7 +463,9 @@
" "
type="target" type="target"
:options=" :options="
getProductProperties(item.target) getProductProperties(
item.target,
)
" "
/> />
</j-form-item> </j-form-item>
@ -547,12 +551,16 @@ import { useMenuStore } from '@/store/menu';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import MSelect from '../../components/MSelect/index.vue'; import MSelect from '../../components/MSelect/index.vue';
import { _deploy } from '@/api/device/product'; import { _deploy } from '@/api/device/product';
import { usePermissionStore } from '@/store/permission';
const menuStory = useMenuStore(); const menuStory = useMenuStore();
const route = useRoute(); const route = useRoute();
const formRef = ref(); const formRef = ref();
const hasPermission = usePermissionStore().hasPermission;
const productPermission = () => hasPermission(`device/Product:action`);
const modelRef = reactive({ const modelRef = reactive({
id: undefined, id: undefined,
name: undefined, name: undefined,

View File

@ -39,7 +39,7 @@ const props = defineProps({
} }
}) })
const emits = defineEmits(['update:value', 'change']); const emits = defineEmits(['update:value', 'change', 'error']);
const formItemContext = Form.useInjectFormItemContext() const formItemContext = Form.useInjectFormItemContext()
@ -65,6 +65,7 @@ watchEffect(() => {
if(props.value){ if(props.value){
formTouchOff() formTouchOff()
} }
emits('error', props.value)
} }
}) })

View File

@ -3,7 +3,7 @@
<div style="padding: 30px;"> <div style="padding: 30px;">
<div style="display: flex; padding-bottom: 24px; margin-bottom: 24px; border-bottom: 1px solid #E4E7F6"> <div style="display: flex; padding-bottom: 24px; margin-bottom: 24px; border-bottom: 1px solid #E4E7F6">
<j-avatar :size="100" :src="userInfos.avatar"></j-avatar> <j-avatar :size="100" :src="userInfos.avatar"></j-avatar>
<div style="margin-left: 24px;"> <div style="margin-left: 24px; max-width: 280px;" >
<div class="name"><j-ellipsis>{{ userInfos.name }}</j-ellipsis></div> <div class="name"><j-ellipsis>{{ userInfos.name }}</j-ellipsis></div>
<div class="subTitle"><j-ellipsis>用户名: {{ userInfos?.username }}</j-ellipsis></div> <div class="subTitle"><j-ellipsis>用户名: {{ userInfos?.username }}</j-ellipsis></div>
<!-- <div class="subTitle">账号ID: {{ userInfos?.id }}</div> --> <!-- <div class="subTitle">账号ID: {{ userInfos?.id }}</div> -->

View File

@ -8,10 +8,10 @@
@change="onChange" @change="onChange"
:pagination="{ :pagination="{
current: (dataSource?.pageIndex || 0) + 1, current: (dataSource?.pageIndex || 0) + 1,
pageSize: dataSource?.pageSize || 10, pageSize: dataSource?.pageSize || 12,
showSizeChanger: true, showSizeChanger: true,
total: dataSource?.total || 0, total: dataSource?.total || 0,
pageSizeOptions: ['8', '12', '24', '60', '100'] pageSizeOptions: ['12', '24', '48', '96']
}" }"
> >
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
@ -92,7 +92,7 @@ const _props = defineProps({
const instanceStore = useInstanceStore(); const instanceStore = useInstanceStore();
const dataSource = ref({ const dataSource = ref({
pageIndex: 0, pageIndex: 0,
pageSize: 10, pageSize: 12,
data: [], data: [],
total: 0 total: 0
}); });
@ -158,7 +158,7 @@ watch(
([newVal]) => { ([newVal]) => {
if (newVal) { if (newVal) {
queryPropertyData({ queryPropertyData({
pageSize: _props.data.valueType?.type === 'file' ? 5 : 10, pageSize: 12,
pageIndex: 0, pageIndex: 0,
}); });
} }

View File

@ -86,7 +86,9 @@
" "
:class="valueClass" :class="valueClass"
> >
{{ JSON.stringify(value?.formatValue) }} <div style='width: 100%; white-space: normal;'>
<j-ellipsis>{{ JSON.stringify(value?.formatValue) }}</j-ellipsis>
</div>
</div> </div>
<div v-else :class="valueClass"> <div v-else :class="valueClass">
<div style='width: 100%;white-space: normal;'> <div style='width: 100%;white-space: normal;'>

View File

@ -11,16 +11,21 @@
<j-popconfirm-modal <j-popconfirm-modal
v-if="myValue != 'manual'" v-if="myValue != 'manual'"
@confirm="confirm" @confirm="confirm"
:bodyStyle="{width: '450px', height: myValue === 'rule' ? '300px' : '80px'}" :bodyStyle="{
width: '450px',
height: myValue === 'rule' ? '300px' : '80px',
}"
> >
<template #content> <template #content>
<j-scrollbar v-if="myValue"> <j-scrollbar v-if="myValue">
<div style="padding: 0 10px">
<VirtualRule <VirtualRule
:value="value" :value="value"
:source="myValue" :source="myValue"
:dataSource="dataSource" :dataSource="dataSource"
ref="virtualRuleRef" ref="virtualRuleRef"
/> />
</div>
</j-scrollbar> </j-scrollbar>
</template> </template>
<j-button :disabled="!myValue" type="link" style="padding: 4px 8px"> <j-button :disabled="!myValue" type="link" style="padding: 4px 8px">
@ -33,7 +38,7 @@
<script setup lang="ts" name="MetadataSource"> <script setup lang="ts" name="MetadataSource">
import { isNoCommunity } from '@/utils/utils'; import { isNoCommunity } from '@/utils/utils';
import VirtualRule from './VirtualRule/index.vue'; import VirtualRule from './VirtualRule/index.vue';
import { Form } from 'jetlinks-ui-components' import { Form } from 'jetlinks-ui-components';
const PropertySource: { label: string; value: string }[] = isNoCommunity const PropertySource: { label: string; value: string }[] = isNoCommunity
? [ ? [
@ -82,8 +87,8 @@ const props = defineProps({
}, },
target: { target: {
type: String, type: String,
default: undefined default: undefined,
} },
}); });
const emit = defineEmits<Emit>(); const emit = defineEmits<Emit>();
@ -94,34 +99,30 @@ const type = ref<string>('');
const virtualRuleRef = ref<any>(null); const virtualRuleRef = ref<any>(null);
const disabled = computed(() => { const disabled = computed(() => {
if (props.target === 'device') { if (props.target === 'device') {
return true return true;
} }
return props.noEdit?.length ? props.noEdit.includes(props.value._sortIndex) : false return props.noEdit?.length
}) ? props.noEdit.includes(props.value._sortIndex)
: false;
});
const updateValue = (data: any) => { const updateValue = (data: any) => {
emit('update:value', { emit('update:value', {
...props.value, ...props.value,
expands: { expands: {
...(props.value?.expands || {}), ...(props.value?.expands || {}),
...data ...data,
} },
}) });
formItemContext.onFieldChange() formItemContext.onFieldChange();
} };
const onChange = (keys: SourceType) => { const onChange = (keys: SourceType) => {
myValue.value = keys; myValue.value = keys;
updateValue({ updateValue({
source: keys, source: keys,
type: type: keys === 'manual' ? ['write'] : keys === 'rule' ? ['report'] : [],
keys === 'manual'
? ['write']
: keys === 'rule'
? ['report']
: [],
}); });
}; };
@ -133,11 +134,11 @@ const confirm = async () => {
if (data) { if (data) {
updateValue({ updateValue({
source: myValue.value, source: myValue.value,
...data ...data,
}); });
resolve(true); resolve(true);
} else { } else {
reject() reject();
} }
}); });
}; };

View File

@ -57,7 +57,6 @@
<Ellipsis <Ellipsis
style=" style="
width: calc(100% - 100px); width: calc(100% - 100px);
margin-bottom: 20px;
" "
> >
<span class="card-title"> <span class="card-title">
@ -113,16 +112,15 @@
<Ellipsis <Ellipsis
style=" style="
width: calc(100% - 10px); width: calc(100% - 10px);
display: flex;
margin-top: 4px;
" "
:lineClamp="2"
> >
<span> <div>
{{ {{
slotProps.protocolDetail slotProps.protocolDetail
.name .name
}} }}
</span> </div>
</Ellipsis> </Ellipsis>
</j-col> </j-col>
</j-row> </j-row>

View File

@ -14,7 +14,9 @@
:params="params" :params="params"
:rowSelection="{ :rowSelection="{
selectedRowKeys: _selectedRowKeys, selectedRowKeys: _selectedRowKeys,
onChange: onSelectChange, onSelect: onSelectChange,
onSelectAll: selectAll,
onSelectNone: cancelSelectAll,
}" }"
> >
<template #headerTitle> <template #headerTitle>
@ -246,10 +248,44 @@ const listRef = ref();
const _selectedRowKeys = ref<string[]>([]); const _selectedRowKeys = ref<string[]>([]);
const bindVis = ref(false); const bindVis = ref(false);
const onSelectChange = (keys: string[]) => { const channelIdMap = new Map();
_selectedRowKeys.value = [...keys]; const onSelectChange = (row: any,selected:Boolean) => {
const arr = new Set(_selectedRowKeys.value);
if(selected){
arr.add(row.id)
channelIdMap.set(row.id,row.channelId)
}else{
arr.delete(row.id)
channelIdMap.delete(row.id)
}
_selectedRowKeys.value = [...arr.values()];
}; };
const selectAll = (selected: Boolean, selectedRows: any,changeRows:any) => {
if (selected) {
changeRows.map((i: any) => {
if (!_selectedRowKeys.value.includes(i.id)) {
_selectedRowKeys.value.push(i.id)
channelIdMap.set(i.id,i.channelId)
}
})
} else {
const arr = changeRows.map((item: any) => item.id)
const _ids: string[] = [];
_selectedRowKeys.value.map((i: any) => {
if (!arr.includes(i)) {
_ids.push(i)
}else{
channelIdMap.delete(i)
}
})
_selectedRowKeys.value = _ids;
}
}
const cancelSelectAll = () =>{
_selectedRowKeys.value = [];
channelIdMap.clear();
}
/** /**
* 表格操作按钮 * 表格操作按钮
* @param data 表格数据项 * @param data 表格数据项
@ -296,15 +332,16 @@ const handleMultipleUnbind = async () => {
onlyMessage('请先选择需要解绑的通道列表', 'error'); onlyMessage('请先选择需要解绑的通道列表', 'error');
return; return;
} }
const channelIds = listRef.value?._dataSource // const channelIds = listRef.value?._dataSource
.filter((f: any) => _selectedRowKeys.value.includes(f.id)) // .filter((f: any) => _selectedRowKeys.value.includes(f.id))
.map((m: any) => m.channelId); // .map((m: any) => m.channelId);
const resp = await CascadeApi.unbindChannel( const resp = await CascadeApi.unbindChannel(
route.query.id as string, route.query.id as string,
channelIds, [...channelIdMap.values()]
); );
if (resp.success) { if (resp.success) {
onlyMessage('操作成功!'); onlyMessage('操作成功!');
_selectedRowKeys.value = []
listRef.value?.reload(); listRef.value?.reload();
} else { } else {
onlyMessage('操作失败!', 'error'); onlyMessage('操作失败!', 'error');

View File

@ -46,9 +46,11 @@
</slot> </slot>
</template> </template>
<template #content> <template #content>
<h3 class="card-item-content-title"> <Ellipsis style="width: calc(100% - 100px);">
<h3 style="font-size: 16px;font-weight: 700;color: #315efb;">
{{ slotProps.name }} {{ slotProps.name }}
</h3> </h3>
</Ellipsis>
<j-row> <j-row>
<j-col :span="12"> <j-col :span="12">
<div class="card-item-content-text"> <div class="card-item-content-text">

View File

@ -98,7 +98,7 @@ watchEffect(() => {
}); });
watchEffect(() => { watchEffect(() => {
if(props?.template?.template?.sendTo) { if(props?.template?.template?.sendTo && Array.isArray(props?.template?.template?.sendTo) && props?.template?.template?.sendTo?.length) {
emit('change', { sendTo: props?.template?.template?.sendTo?.join(' ') }); emit('change', { sendTo: props?.template?.template?.sendTo?.join(' ') });
} }
}); });

View File

@ -154,6 +154,7 @@ const onValChange = (val: any, type: string) => {
} else if (type === 'templateId') { } else if (type === 'templateId') {
formModel.variables = []; formModel.variables = [];
} }
console.log(val)
formModel.options = { formModel.options = {
...unref(formModel.options), ...unref(formModel.options),
...val, ...val,