Merge branch 'dev'

# Conflicts:
#	package.json
This commit is contained in:
xieyonghong 2023-05-19 17:59:23 +08:00
commit 23becbc2f1
18 changed files with 161 additions and 152 deletions

View File

@ -25,7 +25,7 @@
"event-source-polyfill": "^1.0.31", "event-source-polyfill": "^1.0.31",
"global": "^4.4.0", "global": "^4.4.0",
"jetlinks-store": "^0.0.3", "jetlinks-store": "^0.0.3",
"jetlinks-ui-components": "^1.0.16", "jetlinks-ui-components": "^1.0.18",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"less": "^4.1.3", "less": "^4.1.3",
"less-loader": "^11.1.0", "less-loader": "^11.1.0",

View File

@ -1,7 +1,7 @@
import server from '@/utils/request' import server from '@/utils/request'
// 获取记录列表 // 获取记录列表
export const getList_api = (data: object): any => server.get(`/notifications/_query`, encodeParams(data)) export const getList_api = (data: object): any => server.post(`/notifications/_query`, data)
// 获取未读记录列表 // 获取未读记录列表
export const getListByUnRead_api = (data: object): any => server.post(`/notifications/_query`, data) export const getListByUnRead_api = (data: object): any => server.post(`/notifications/_query`, data)
// 修改记录状态 // 修改记录状态

View File

@ -2,7 +2,7 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
type DepartmentStateType = { type DepartmentStateType = {
productId: string; productId?: string[];
optType: string | undefined; optType: string | undefined;
crossPageKeys: string[]; crossPageKeys: string[];
changedApis: any; changedApis: any;
@ -11,7 +11,7 @@ type DepartmentStateType = {
export const useDepartmentStore = defineStore({ export const useDepartmentStore = defineStore({
id: 'department', id: 'department',
state: (): DepartmentStateType => ({ state: (): DepartmentStateType => ({
productId: '', productId: undefined,
// 设备资产分配弹窗操作类型: // 设备资产分配弹窗操作类型:
// 1. optType === 'handle': 手动点击资产分配按钮; // 1. optType === 'handle': 手动点击资产分配按钮;
// 2. optType === ': 产品资产分配后, 自动弹出设备资产分配 // 2. optType === ': 产品资产分配后, 自动弹出设备资产分配
@ -20,7 +20,7 @@ export const useDepartmentStore = defineStore({
changedApis: {}, changedApis: {},
}), }),
actions: { actions: {
setProductId(value: string) { setProductId(value?: string[]) {
this.productId = value; this.productId = value;
}, },
setType(value: string | undefined) { setType(value: string | undefined) {

View File

@ -186,7 +186,7 @@ const endianData = computed(() => {
if (endian === 'BIG') { if (endian === 'BIG') {
return endianIn === 'BIG' ? 'ABCD' : 'BADC'; return endianIn === 'BIG' ? 'ABCD' : 'BADC';
} else { } else {
return endianIn === 'BIG' ? 'CDBA' : 'DCBA'; return endianIn === 'BIG' ? 'CDAB' : 'DCBA';
} }
} else { } else {
return endian === 'BIG' ? 'ABCD' : 'DCBA'; return endian === 'BIG' ? 'ABCD' : 'DCBA';

View File

@ -14,8 +14,9 @@
model="TABLE" model="TABLE"
:params="queryParams" :params="queryParams"
:defaultParams="{ :defaultParams="{
'sorts[0].name': 'notifyTime', sorts: [{
'sorts[0].order': 'desc', name: 'notifyTime', order: 'desc'
}]
}" }"
> >
<template #topicProvider="slotProps"> <template #topicProvider="slotProps">
@ -95,6 +96,7 @@ import moment from 'moment';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
import { useUserInfo } from '@/store/userInfo'; import { useUserInfo } from '@/store/userInfo';
import { useRouterParams } from '@/utils/hooks/useParams'; import { useRouterParams } from '@/utils/hooks/useParams';
import dayjs from 'dayjs'
const { updateAlarm } = useUserInfo(); const { updateAlarm } = useUserInfo();
const columns = [ const columns = [
@ -132,7 +134,7 @@ const columns = [
dataIndex: 'notifyTime', dataIndex: 'notifyTime',
key: 'notifyTime', key: 'notifyTime',
search: { search: {
type: 'date', type: 'date'
}, },
scopedSlots: true, scopedSlots: true,
ellipsis: true, ellipsis: true,

View File

@ -130,6 +130,7 @@ import { queryList, getAccessConfig } from '@/api/device/product'
import { message } from 'jetlinks-ui-components' import { message } from 'jetlinks-ui-components'
import { useMenuStore } from '@/store/menu'; import { useMenuStore } from '@/store/menu';
import { getProductByPluginId } from '@/api/link/plugin' import { getProductByPluginId } from '@/api/link/plugin'
import { getProviders } from '@/api/link/accessConfig'
type Emit = { type Emit = {
(e: 'submit', data: any): void (e: 'submit', data: any): void
@ -219,6 +220,21 @@ const columns = [
type: 'string', type: 'string',
}, },
}, },
{
title: '网关类型',
dataIndex: 'provider',
key: 'provider',
search: {
type: 'select',
options: () => {
return new Promise(resolve => {
getProviders().then(res => {
resolve(res.result?.map((item: any) => ({ ...item, label: item.name, value: item.id })) || [])
})
})
},
},
},
{ {
title: '状态', title: '状态',
dataIndex: 'state', dataIndex: 'state',

View File

@ -309,11 +309,13 @@ const submitData = () => {
.validate() .validate()
.then(async () => { .then(async () => {
// //
loading.value = true
if (props.isAdd === 1) { if (props.isAdd === 1) {
if (form.id === '') { if (form.id === '') {
form.id = undefined; form.id = undefined;
} }
const res = await addProduct(form); const res = await addProduct(form);
loading.value = false
if (res.status === 200) { if (res.status === 200) {
message.success('保存成功!'); message.success('保存成功!');
visible.value = false; visible.value = false;
@ -331,6 +333,7 @@ const submitData = () => {
? form.classifiedName ? form.classifiedName
: (form.classifiedName = ''); : (form.classifiedName = '');
const res = await editProduct(form); const res = await editProduct(form);
loading.value = false
if (res.status === 200) { if (res.status === 200) {
message.success('保存成功!'); message.success('保存成功!');
emit('success'); emit('success');

View File

@ -281,9 +281,7 @@ const pluginSearch = (val: string) => {
} }
const AccessChange = (id: string) => { const AccessChange = (id: string) => {
if (!props.data.id) {
AccessCurrent.value = id; AccessCurrent.value = id;
}
}; };
const addPlugin = () => { const addPlugin = () => {

View File

@ -3,9 +3,10 @@
class="add-device-or-product-dialog-container" class="add-device-or-product-dialog-container"
title="绑定" title="绑定"
width="1440px" width="1440px"
:maskClosable="false"
@ok="confirm" @ok="confirm"
:confirmLoading="loading" :confirmLoading="loading"
@cancel="emits('update:visible', false)" @cancel="cancel"
visible visible
> >
<h5 class="row"> <h5 class="row">
@ -28,9 +29,9 @@
<pro-search <pro-search
type="simple" type="simple"
:columns="props.queryColumns" :columns="searchColumns"
target="category" target="category-bind-modal"
@search="(params:any)=>queryParams = {...params}" @search="search"
/> />
<j-pro-table <j-pro-table
ref="tableRef" ref="tableRef"
@ -175,7 +176,6 @@ const confirm = () => {
return message.warning('请先勾选数据'); return message.warning('请先勾选数据');
} }
console.log('table.selectedRows: ', table.selectedRows);
const params = table.selectedRows.map((item: any) => ({ const params = table.selectedRows.map((item: any) => ({
targetType: 'org', targetType: 'org',
targetId: props.parentId, targetId: props.parentId,
@ -187,8 +187,8 @@ const confirm = () => {
), ),
})); }));
// , , // ,
departmentStore.setProductId(params[0].assetIdList[0]); departmentStore.setProductId(table.selectedRows.map((item: any) => item.id));
loading.value = true; loading.value = true;
bindDeviceOrProductList_api(props.assetType, params) bindDeviceOrProductList_api(props.assetType, params)
@ -216,6 +216,26 @@ const columns = props.queryColumns.filter(
(item) => item.dataIndex !== 'action', (item) => item.dataIndex !== 'action',
); );
const searchColumns = computed(() => {
return props.queryColumns.map(item => {
if (departmentStore.productId) {
if (item.dataIndex === 'productName') {
item.search.first = true
item.search.componentProps = {
mode: 'multiple',
"max-tag-count": "responsive"
}
item.search.defaultTermType = 'eq'
item.search.defaultOnceValue = departmentStore.productId
} else if (item.search && 'first' in item.search) {
delete item.search.first
}
}
return item
})
})
const queryParams = ref({}); const queryParams = ref({});
const table: any = { const table: any = {
_selectedRowKeys: ref<string[]>([]), // id _selectedRowKeys: ref<string[]>([]), // id
@ -234,19 +254,6 @@ const table: any = {
// //
if (bulkBool.value) { if (bulkBool.value) {
// //
// let newPermission = uniq([
// ...item.selectPermissions,
// ...bulkList.value,
// ]);
// const allPermissions = item.permissionList.map(
// (item: any) => item.value,
// );
// newPermission = intersection(
// newPermission,
// allPermissions,
// );
// item.selectPermissions = newPermission;
// fix: bug#10756 // fix: bug#10756
item.selectPermissions = n[1]; item.selectPermissions = n[1];
// //
@ -390,67 +397,13 @@ const table: any = {
}); });
}, },
); );
// getPermission_api(props.assetType, ids, parentId).then(
// (perResp: any) => {
// console.log('perResp: ', perResp);
// console.log('props.allPermission: ', props.allPermission);
// const permissionObj = {};
// perResp.result.forEach((item: any) => {
// permissionObj[item.assetId] = props.allPermission
// .filter((permission) =>
// item.allPermissions.includes(permission.id),
// )
// .map((item) => ({
// label: item.name,
// value: item.id,
// disabled: true,
// }));
// });
// data.forEach((item) => {
// item.permissionList = permissionObj[item.id];
// item.selectPermissions = ['read'];
// //
// if (props.assetType === 'product') {
// item.state = {
// value:
// item.state === 1
// ? 'online'
// : item.state === 0
// ? 'offline'
// : '',
// text:
// item.state === 1
// ? ''
// : item.state === 0
// ? ''
// : '',
// };
// }
// });
// resolve({
// code: 200,
// result: {
// data: data,
// pageIndex,
// pageSize,
// total,
// },
// status: 200,
// });
// },
// );
}); });
}), }),
// //
requestFun: async (oParams: any) => { requestFun: async (oParams: any) => {
queryCount.value += 1; queryCount.value += 1;
if (props.parentId) { if (props.parentId) {
const terms = [ let terms = [{
{
terms: [
{
column: 'id', column: 'id',
termType: 'dim-assets$not', termType: 'dim-assets$not',
value: { value: {
@ -462,27 +415,22 @@ const table: any = {
}, },
], ],
}, },
}, type: 'and'
{ }]
column: 'productId$product-info',
type: 'and',
value: `id is ${departmentStore.productId}`,
},
],
},
];
if ( // if (
props.assetType !== 'device' || // props.assetType !== 'device' ||
!departmentStore.productId || // !departmentStore.productId ||
queryCount.value > 1 || // queryCount.value > 1 ||
departmentStore.optType === 'handle' // departmentStore.optType === 'handle'
) { // ) {
// |id|(queryCount+1)|, id // // |id|(queryCount+1)|, id
terms[0].terms.pop(); // terms[0].terms.pop();
// }
if (oParams.terms && oParams.terms.length > 0) {
terms = [ ...oParams.terms, ...terms]
} }
if (oParams.terms && oParams.terms.length > 0)
terms.unshift({ terms: oParams.terms });
const params = { const params = {
...oParams, ...oParams,
sorts: [{ name: 'createTime', order: 'desc' }], sorts: [{ name: 'createTime', order: 'desc' }],
@ -526,6 +474,15 @@ const selectChange = (keys: string[], rows: any[]) => {
table.selectedRows = rows; table.selectedRows = rows;
table._selectedRowKeys.value = keys; table._selectedRowKeys.value = keys;
}; };
const cancel = () => {
departmentStore.setProductId()
emits('update:visible', false)
}
const search = (query: any) => {
queryParams.value = query
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -2,6 +2,7 @@
<j-modal <j-modal
visible visible
:title="title" :title="title"
:maskClosable="false"
width="520px" width="520px"
@cancel="emits('update:visible', false)" @cancel="emits('update:visible', false)"
@ok="confirm" @ok="confirm"
@ -60,6 +61,7 @@ import {
addDepartment_api, addDepartment_api,
updateDepartment_api, updateDepartment_api,
} from '@/api/system/department'; } from '@/api/system/department';
import { onlyMessage } from '@/utils/comm'
type treeType = { type treeType = {
id: string; id: string;
@ -91,6 +93,7 @@ const confirm = () => {
?.validate() ?.validate()
.then(() => form.submit()) .then(() => form.submit())
.then((resp: any) => { .then((resp: any) => {
onlyMessage('操作成功')
emits('refresh', resp.result.id); emits('refresh', resp.result.id);
emits('update:visible', false); emits('update:visible', false);
}) })

View File

@ -4,6 +4,7 @@
title="编辑" title="编辑"
width="500px" width="500px"
@ok="confirm" @ok="confirm"
:maskClosable="false"
:confirmLoading="loading" :confirmLoading="loading"
visible visible
@cancel="emits('update:visible', false)" @cancel="emits('update:visible', false)"

View File

@ -32,7 +32,12 @@
:fieldNames="{ key: 'id' }" :fieldNames="{ key: 'id' }"
> >
<template #title="{ name, data }"> <template #title="{ name, data }">
<span>{{ name }}</span> <div class='department-tree-item-content'>
<span class='title'>
<j-ellipsis>
{{ name }}
</j-ellipsis>
</span>
<span class="func-btns" @click="(e) => e.stopPropagation()"> <span class="func-btns" @click="(e) => e.stopPropagation()">
<PermissionButton <PermissionButton
:hasPermission="`${permission}:update`" :hasPermission="`${permission}:update`"
@ -72,6 +77,7 @@
<AIcon type="DeleteOutlined" /> <AIcon type="DeleteOutlined" />
</PermissionButton> </PermissionButton>
</span> </span>
</div>
</template> </template>
</jTree> </jTree>
<j-empty v-else description="暂无数据" /> <j-empty v-else description="暂无数据" />
@ -215,13 +221,15 @@ const openDialog = (row: any = {}) => {
dialog.selectItem = { ...row, sortIndex }; dialog.selectItem = { ...row, sortIndex };
dialog.visible = true; dialog.visible = true;
}; };
init();
function init() { const init = () => {
getTree(save ? openDialog : undefined); getTree(save ? openDialog : undefined);
watch(selectedKeys, (n) => { watch(selectedKeys, (n) => {
emits('change', n[0]); emits('change', n[0]);
}); });
} }
init();
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@ -246,17 +254,6 @@ function init() {
flex: 1 1 auto; flex: 1 1 auto;
.ant-tree-title { .ant-tree-title {
display: flex;
justify-content: space-between;
align-items: center;
.func-btns {
display: none;
font-size: 14px;
.ant-btn-link {
padding: 0 4px;
height: 24px;
}
}
&:hover { &:hover {
.func-btns { .func-btns {
display: block; display: block;
@ -271,6 +268,24 @@ function init() {
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
.department-tree-item-content {
display: flex;
align-items: center;
.title {
width: calc(100% - 80px);
}
.func-btns {
display: none;
font-size: 14px;
width: 80px;
:deep(.ant-btn-link) {
padding: 0 4px;
height: 24px;
}
}
}
.loading { .loading {
display: flex; display: flex;
width: 100%; width: 100%;

View File

@ -4,23 +4,33 @@
title="绑定" title="绑定"
width="520px" width="520px"
@ok="handleOk" @ok="handleOk"
:maskClosable="false"
class="edit-dialog-container" class="edit-dialog-container"
@cancel="emits('update:visible',false)" @cancel="cancel"
> >
是否继续分配产品下的具体设备 是否继续分配产品下的具体设备
</j-modal> </j-modal>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const emits = defineEmits(['confirm','update:visible']); import { useDepartmentStore } from 'store/department'
const emits = defineEmits(['confirm','update:visible']);
const departmentStore = useDepartmentStore();
const props = defineProps<{ const props = defineProps<{
visible: boolean; visible: boolean;
}>(); }>();
const handleOk = () => { const handleOk = () => {
emits('confirm'); emits('confirm');
emits('update:visible',false) emits('update:visible',false)
}; };
const cancel = () => {
departmentStore.setProductId()
emits('update:visible',false)
}
</script> </script>
<style scoped></style> <style scoped></style>

View File

@ -269,7 +269,7 @@ const columns = [
rename: 'productId$product-info', rename: 'productId$product-info',
type: 'select', type: 'select',
handleValue(value: string) { handleValue(value: string) {
return `id is ${value}`; return `id in ${value.toString()}`;
}, },
options: () => options: () =>
new Promise((resolve) => { new Promise((resolve) => {

View File

@ -208,7 +208,7 @@
v-if="dialogs.addShow" v-if="dialogs.addShow"
v-model:visible="dialogs.addShow" v-model:visible="dialogs.addShow"
:query-columns="columns" :query-columns="columns"
:parent-id="props.parentId" :parent-id="parentId"
:all-permission="tableData.permissionList" :all-permission="tableData.permissionList"
asset-type="product" asset-type="product"
@confirm="table.addConfirm" @confirm="table.addConfirm"
@ -218,7 +218,7 @@
v-model:visible="dialogs.editShow" v-model:visible="dialogs.editShow"
:ids="dialogs.selectIds" :ids="dialogs.selectIds"
:permission-list="dialogs.permissList" :permission-list="dialogs.permissList"
:parent-id="props.parentId" :parent-id="parentId"
:all-permission="tableData.permissionList" :all-permission="tableData.permissionList"
asset-type="product" asset-type="product"
@confirm="table.refresh" @confirm="table.refresh"

View File

@ -317,6 +317,8 @@ const form = reactive({
}; };
form.sourceCode = resp.result.code; form.sourceCode = resp.result.code;
}); });
if (isNoCommunity) {
// //
getMenuTree_api({ paging: false }).then((resp: any) => { getMenuTree_api({ paging: false }).then((resp: any) => {
form.treeData = resp.result; form.treeData = resp.result;
@ -328,6 +330,7 @@ const form = reactive({
value: item.id, value: item.id,
})); }));
}); });
}
}, },
checkCode: async (_rule: Rule, value: string): Promise<any> => { checkCode: async (_rule: Rule, value: string): Promise<any> => {
if (!value) return Promise.reject(''); if (!value) return Promise.reject('');

View File

@ -2,6 +2,7 @@
<j-modal <j-modal
visible visible
:title="dialogTitle" :title="dialogTitle"
:maskClosable="false"
width="675px" width="675px"
@ok="confirm" @ok="confirm"
@cancel="emits('update:visible', false)" @cancel="emits('update:visible', false)"
@ -97,7 +98,7 @@
<j-select <j-select
v-model:value="form.data.roleIdList" v-model:value="form.data.roleIdList"
mode="multiple" mode="multiple"
style="width: 100%" style="width: calc(100% - 40px)"
placeholder="请选择角色" placeholder="请选择角色"
:options="form.roleOptions" :options="form.roleOptions"
></j-select> ></j-select>
@ -115,7 +116,7 @@
<j-tree-select <j-tree-select
v-model:value="form.data.orgIdList" v-model:value="form.data.orgIdList"
show-search show-search
style="width: 100%" style="width: calc(100% - 40px)"
placeholder="请选择组织" placeholder="请选择组织"
:tree-data="form.departmentOptions" :tree-data="form.departmentOptions"
:fieldNames="{ label: 'name', value: 'id' }" :fieldNames="{ label: 'name', value: 'id' }"

View File

@ -94,9 +94,9 @@ export default defineConfig(({ mode}) => {
[env.VITE_APP_BASE_API]: { [env.VITE_APP_BASE_API]: {
// target: 'http://192.168.32.226:8844', // target: 'http://192.168.32.226:8844',
// target: 'http://192.168.32.244:8881', // target: 'http://192.168.32.244:8881',
target: 'http://120.77.179.54:8844', // 120测试 // target: 'http://120.77.179.54:8844', // 120测试
// target: 'http://192.168.33.46:8844', // 本地开发环境 target: 'http://192.168.33.46:8844', // 本地开发环境
ws: 'ws://120.77.179.54:8844', ws: 'ws://192.168.33.46:8844',
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '') rewrite: (path) => path.replace(/^\/api/, '')
} }