Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev

This commit is contained in:
jackhoo_98 2023-03-31 18:03:18 +08:00
commit ae2758b5ba
21 changed files with 335 additions and 57 deletions

View File

@ -0,0 +1,9 @@
import server from '@/utils/request';
export const getModule = () => server.get('/license/module');
export const licenseInit = (data:any) =>server.post('/license/init',data);
export const getLicense = () => server.get('/license');
export const initPage = () => server.get('/user/settings/init');

View File

@ -47,8 +47,7 @@ const emit = defineEmits<Emits>()
const props = defineProps({
value: {
type: Object as PropType<ModelValueType>,
default: () => ({
})
default: () => ({})
},
name: {
type: Array as PropType<(string| number)[]>,
@ -67,6 +66,15 @@ onMounted(() => {
})
})
watchEffect(() => {
if (typeof props.value.trueValue === 'boolean') {
props.value.trueValue = String(props.value.trueValue)
}
if (typeof props.value.falseValue === 'boolean') {
props.value.falseValue = String(props.value.falseValue)
}
})
</script>
<style lang="less" scoped>
.boolean-param {

View File

@ -1,6 +1,7 @@
export const LoginPath = '/login'
export const InitHomePath = '/init-home'
export const AccountCenterBindPath = '/account/center/bind'
export const InitLicense = '/init-license'
export const AccountMenu = {
path: '/account',
@ -51,7 +52,7 @@ export const AccountMenu = {
}
export default [
{ path: '/*', redirect: '/'},
{ path: '/*', redirect: '/' },
{
path: LoginPath,
component: () => import('@/views/user/Login/index.vue')
@ -61,8 +62,12 @@ export default [
component: () => import('@/views/account/Center/bind/index.vue')
},
{
path: InitHomePath, // 初始化
component: () => import('@/views/init-home/index.vue')
path: InitHomePath, // 初始化
component: () => import('@/views/init-home/index.vue')
},
{
path: InitLicense,
component: () => import('@/views/system/License/index.vue')
}
]

View File

@ -4,7 +4,7 @@
<div class="content">
<div class="title">第三方账户绑定</div>
<!-- 已登录-绑定三方账号 -->
<template v-if="!token">
<template v-if="!!token">
<div class="info">
<j-card style="width: 280px">
<template #title>
@ -14,9 +14,14 @@
</div>
</template>
<div class="info-body">
<img :src="getImage('/bind/jetlinksLogo.png')" />
<p>账号admin</p>
<p>用户名超级管理员</p>
<img
:src="
user?.avatar ||
getImage('/bind/jetlinksLogo.png')
"
/>
<p>账号{{ user?.username }}</p>
<p>用户名{{ user?.name }}</p>
</div>
</j-card>
<img :src="getImage('/bind/Vector.png')" />
@ -30,12 +35,13 @@
<div class="info-body">
<img
:src="
accountInfo?.avatar ||
getImage('/bind/wechat-webapp.png')
iconMap.get(
bindUser?.applicationProvider,
) || getImage('/apply/provider1.png')
"
/>
<p>用户名-</p>
<p>名称{{ accountInfo?.name || '-' }}</p>
<p>账号{{ bindUser?.result?.username || '-' }}</p>
<p>用户名{{ bindUser?.result?.name || '-' }}</p>
</div>
</j-card>
</div>
@ -54,10 +60,18 @@
class="arrow"
:src="getImage('/bind/Vector.png')"
/>
<img :src="getImage('/bind/wechat-webapp.png')" />
<img
:src="iconMap.get(bindUser?.applicationProvider)"
/>
</div>
<div class="desc">
你已通过微信授权,完善以下登录信息即可以完成绑定
你已通过
{{
bindUser?.type === 'dingtalk-ent-app'
? '钉钉'
: '微信'
}}
授权,完善以下登录信息即可以完成绑定
</div>
<div class="login-form">
<j-form layout="vertical">
@ -120,7 +134,7 @@ import { Form } from 'ant-design-vue';
import { message } from 'ant-design-vue';
import { applicationInfo, bindAccount } from '@/api/bind';
import { code, authLogin } from '@/api/login';
import { code, authLogin, userDetail } from '@/api/login';
const useForm = Form.useForm;
@ -130,24 +144,44 @@ interface formData {
verifyCode: string;
}
const iconMap = new Map();
iconMap.set('dingtalk-ent-app', getImage('/notice/dingtalk.png'));
iconMap.set('wechat-webapp', getImage('/notice/wechat.png'));
iconMap.set('internal-standalone', getImage('/apply/provider1.png'));
iconMap.set('third-party', getImage('/apply/provider5.png'));
const token = computed(() => LocalStore.get(TOKEN_KEY));
//
/**
* 用户信息
*/
const user = ref();
const getDetail = () => {
if (!token) return;
userDetail().then((res: any) => {
user.value = res?.result;
});
};
getDetail();
/**
* 三方应用信息
*/
const bindUser = ref();
const getAppInfo = async () => {
const code = getUrlCode();
const { result } = await applicationInfo(code);
bindUser.value = result;
};
getAppInfo();
/**
* 获取url参数
*/
const getUrlCode = () => {
const url = new URLSearchParams(window.location.href);
return url.get('code') as string;
};
//
const accountInfo = ref({
avatar: '',
name: '',
});
const getAppInfo = async () => {
const code = getUrlCode();
const res = await applicationInfo(code);
accountInfo.value = res?.result?.result;
};
getAppInfo();
/**
* 立即绑定

View File

@ -13,6 +13,9 @@
<j-input-number v-model:value="_value.scale" size="small" :min="0" :max="2147483647" :precision="0"
style="width: 100%" placeholder="请输入精度"></j-input-number>
</j-form-item>
<j-form-item label="时间格式" :name="name.concat(['format'])" v-if="['date'].includes(_value.type)" v-show="false">
<j-input v-model:value="_value.format" size="small"></j-input>
</j-form-item>
<j-form-item label="布尔值" name="booleanConfig" v-if="['boolean'].includes(_value.type)">
<BooleanParam :name="name" v-model:value="_value"></BooleanParam>
</j-form-item>
@ -159,6 +162,9 @@ const changeType = (val: SelectValue) => {
if (['file'].includes(val as string)) {
_value.value.fileType = _value.value.fileType || 'url'
}
if (['date'].includes(val as string)) {
_value.value.format = _value.value.format || 'yyyy-MM-DD HH:mm:ss'
}
emit('changeType', val as string)
}

View File

@ -49,7 +49,7 @@
</j-tooltip>
</j-space>
</template>
<JMonacoEditor v-model="formModel.import" theme="vs" style="height: 300px" lang="javascript"></JMonacoEditor>
<JMonacoEditor v-model="formModel.import" theme="vs" style="height: 300px" lang="json"></JMonacoEditor>
</j-form-item>
</j-form>
</j-modal>
@ -206,14 +206,14 @@ const handleImport = async () => {
loading.value = true
const { id } = route.params || {}
if (data.metadata === 'alink') {
const res = await convertMetadata('from', 'alink', data.import).catch(err => err)
const res = await convertMetadata('from', 'alink', JSON.parse(data.import)).catch(err => err)
if (res.status === 200) {
const metadata = operateLimits(res.result)
let result;
if (props?.type === 'device') {
result = await saveMetadata(id as string, metadata).catch(err => err)
} else {
result = await modify(id as string, { metadata: metadata }).catch(err => err)
result = await modify(id as string, { id, metadata: JSON.stringify(metadata) }).catch(err => err)
}
if (result.success) {
message.success('导入成功')
@ -225,9 +225,9 @@ const handleImport = async () => {
return
}
if (props?.type === 'device') {
instanceStore.refresh(id as string)
await instanceStore.refresh(id as string)
} else {
productStore.refresh(id as string)
await productStore.refresh(id as string)
}
metadataStore.set('importMetadata', true)
// Store.set(SystemConst.GET_METADATA, true)
@ -258,21 +258,21 @@ const handleImport = async () => {
loading.value = false
if (resp.success) {
if (props?.type === 'device') {
const detail = instanceStore.current
detail.metadata = JSON.stringify(paramsDevice)
instanceStore.setCurrent(detail)
// const detail = instanceStore.current
// detail.metadata = JSON.stringify(paramsDevice)
// instanceStore.setCurrent(detail)
message.success('导入成功')
} else {
const detail = productStore.current
detail.metadata = params.metadata
productStore.setCurrent(detail)
// const detail = productStore.current
// detail.metadata = params.metadata
// productStore.setCurrent(detail)
message.success('导入成功')
}
}
if (props?.type === 'device') {
instanceStore.refresh(id as string)
await instanceStore.refresh(id as string)
} else {
productStore.refresh(id as string)
await productStore.refresh(id as string)
}
metadataStore.set('importMetadata', true)
// Store.set(SystemConst.GET_METADATA, true)

View File

@ -66,7 +66,7 @@
<div class="card-item-content-text">
型号
</div>
<div>{{ slotProps.model }}</div>
<Ellipsis>{{ slotProps.model }}</Ellipsis>
</j-col>
<j-col :span="12">
<div class="card-item-content-text">

View File

@ -1236,8 +1236,11 @@ const handleSubmit = () => {
formData.value.variableDefinitions.some((s: any) => !s.name)
)
return;
//
if (formData.value.type === 'email') delete formData.value.configId;
if (formData.value.type === 'email') {
formData.value.template.text = formData.value.template.message;
//
delete formData.value.configId;
}
if (formData.value.template.messageType === 'markdown')
delete formData.value.template.link;
if (formData.value.template.messageType === 'link')

View File

@ -86,6 +86,7 @@ import { storeToRefs } from 'pinia';
import {cloneDeep, flattenDeep, isArray, set} from 'lodash-es'
import { Form } from 'jetlinks-ui-components'
import {treeFilter} from "@/utils/comm";
import { timeTypeKeys } from '@/views/rule-engine/Scene/Save/components/Terms/util'
const sceneStore = useSceneStore()
const { data: formModel } = storeToRefs(sceneStore)
@ -160,7 +161,7 @@ const showDelete = ref(false)
const columnOptions: any = inject('filter-params') //
const termTypeOptions = ref<Array<{ id: string, name: string}>>([]) //
const valueOptions = ref<any[]>([]) //
const arrayParamsKey = ['nbtw', 'btw', 'in', 'nin']
const arrayParamsKey = ['nbtw', 'btw', 'in', 'nin', 'contains_all', 'contains_any', 'not_contains']
const valueColumnOptions = ref<any[]>([])
const tabsOptions = ref<Array<TabsOption>>(
@ -285,7 +286,19 @@ const columnSelect = (e: any) => {
const termsTypeSelect = (e: { key: string, name: string }) => {
const oldValue = isArray(paramsValue.value!.value) ? paramsValue.value!.value[0] : paramsValue.value!.value
const value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue
let value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue
// timeTypeKeys
if (timeTypeKeys.includes(e.key)) {
if (tabsOptions.value[0].component !== 'int') {
value = undefined
}
tabsOptions.value[0].component = 'int'
} else if (!timeTypeKeys.includes(e.key) && tabsOptions.value[0].component == 'int') {
value = undefined
tabsOptions.value[0].component = 'date'
}
paramsValue.value = {
source: paramsValue.value?.source || tabsOptions.value[0].key,
value: value

View File

@ -77,7 +77,7 @@ import DropdownButton from '../DropdownButton'
import { getOption } from '../DropdownButton/util'
import ParamsDropdown, { DoubleParamsDropdown } from '../ParamsDropdown'
import { inject } from 'vue'
import { ContextKey } from './util'
import { ContextKey, arrayParamsKey, timeTypeKeys } from './util'
import { useSceneStore } from 'store/scene'
import { storeToRefs } from 'pinia';
import { Form } from 'jetlinks-ui-components'
@ -157,7 +157,6 @@ const valueOptions = ref<any[]>([]) // 默认手动输入下拉
const metricOption = ref<any[]>([]) // termType
const isMetric = ref<boolean>(false) //
const tabsOptions = ref<Array<TabsOption>>([{ label: '手动输入', key: 'manual', component: 'string' }])
const arrayParamsKey = ['nbtw', 'btw', 'in', 'nin']
const metricsCacheOption = ref<any[]>([]) //
const handOptionByColumn = (option: any) => {
@ -280,7 +279,18 @@ const columnSelect = (option: any) => {
const termsTypeSelect = (e: { key: string, name: string }) => {
const oldValue = isArray(paramsValue.value!.value) ? paramsValue.value!.value[0] : paramsValue.value!.value
const value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue
let value = arrayParamsKey.includes(e.key) ? [ oldValue, undefined ] : oldValue
// timeTypeKeys
if (timeTypeKeys.includes(e.key)) {
if (tabsOptions.value[0].component !== 'int') {
value = undefined
}
tabsOptions.value[0].component = 'int'
} else if (!timeTypeKeys.includes(e.key) && tabsOptions.value[0].component == 'int') {
value = undefined
tabsOptions.value[0].component = 'date'
}
paramsValue.value = {
source: paramsValue.value?.source || tabsOptions.value[0].key,
value: value

View File

@ -1,6 +1,9 @@
import { BranchesThen } from '@/views/rule-engine/Scene/typings'
export const ContextKey = 'columnOptions'
export const arrayParamsKey = ['nbtw', 'btw', 'in', 'nin', 'contains_all', 'contains_any', 'not_contains']
export const timeTypeKeys = ['time_gt_now', 'time_lt_now']
export const handleParamsData = (data: any[], key: string = 'column'): any[] => {
return data?.map(item => {

View File

@ -123,6 +123,7 @@ export const EventEmitter = {
}
export const isActionChange = (_metadata: any, _message: any) => {
console.log(_metadata, _message)
const _properties = _metadata?.properties || [];
const _functions = _metadata?.functions || [];
if (
@ -144,7 +145,7 @@ export const isActionChange = (_metadata: any, _message: any) => {
} else if (_message?.messageType === 'WRITE_PROPERTY') {
const _data = Object.keys(_message?.properties)?.[0]
if (_data) {
const _item = _functions.find((i: any) => i.id === _data);
const _item = _properties.find((i: any) => i.id === _data);
return _item?.id;
}
return false;

View File

@ -43,7 +43,7 @@
:status="slotProps.state?.value"
:statusText="slotProps.state?.text"
:statusNames="{
enabled: 'success',
enabled: 'processing',
disabled: 'error',
}"
>
@ -151,7 +151,7 @@
:status="slotProps.state.value"
:text="slotProps.state.text"
:statusNames="{
enabled: 'success',
enabled: 'processing',
disabled: 'error',
}"
></BadgeStatus>
@ -201,6 +201,7 @@ import { ActionsType } from '@/components/Table';
import { getImage } from '@/utils/comm';
import { useMenuStore } from '@/store/menu';
import { message } from 'jetlinks-ui-components';
import BadgeStatus from '@/components/BadgeStatus/index.vue';
const menuStory = useMenuStore();
const permission = 'system/Apply';

View File

@ -0,0 +1,77 @@
<template>
<FullPage>
<j-card>
<TitleComponent data="基础信息"></TitleComponent>
<div>
<j-descriptions bordered :column="4">
<j-descriptions-item label="Host" :span="4">
{{ info?.host }}
</j-descriptions-item>
<template v-for="i in info?.modules" :key="i">
<j-descriptions-item label="IP" :span="2">
{{ i.ip }}
</j-descriptions-item>
<j-descriptions-item label="Mac" :span="2">
{{ i.mac }}</j-descriptions-item
>
</template>
</j-descriptions>
</div>
<div style="display: flex; margin-top: 10px; align-items: center">
<TitleComponent
data="License"
style="margin-top: 20px"
></TitleComponent>
<slot></slot>
</div>
<j-textarea
placeholder="请输入License"
:rows="10"
v-model:value="license"
>
</j-textarea>
<PermissionButton
type="primary"
key="save"
style="margin-top: 20px"
@click="saveData"
>保存</PermissionButton
>
</j-card>
</FullPage>
</template>
<script lang="ts" setup>
const props = defineProps({
data: {
type: Object,
default: {},
},
licenseData: {
type: String,
default: '',
},
});
let info = ref();
let license = ref();
watch(
() => {
props.data;
},
() => {
info.value = props.data;
},
);
watch(
() => props.licenseData,
() => {
license.value = props.licenseData;
},
);
const emit = defineEmits(['saveData']);
const saveData = () => {
emit('saveData', license.value);
};
</script>
<style lang="less" scoped>
</style>

View File

@ -0,0 +1,40 @@
<template>
<Card :infoData="info" @saveData="saveData" />
</template>
<script lang="ts" setup>
import Card from './component/Card.vue';
import { message } from 'jetlinks-ui-components';
import { getModule, licenseInit, initPage } from '@/api/system/license';
let info = ref();
const saveData = (data: any) => {
if (data) {
save(data);
} else {
message.error('请配置License');
}
};
const getInfo = async () => {
const res = await getModule();
if (res.status === 200) {
info.value = res.result;
}
};
const save = async (data: any) => {
const res: any = await licenseInit(data);
if (res.status === 200) {
message.success('配置成功');
const resp: any = await initPage();
if (resp.status === 200 && !resp.result.length) {
window.location.href = '/#/init-home';
} else {
window.location.href = '/';
}
}
};
onMounted(() => {
getInfo();
});
</script>
<style lang="less" scoped>
</style>

View File

@ -0,0 +1,64 @@
<template>
<page-container>
<Card
:infoData="info"
@saveData="saveData"
:license-data="license"
:licenseTime="licenseTime"
>
<div style="width: 200px">到期时间:{{ licenseTime?.expire }}</div>
</Card>
</page-container>
</template>
<script lang="ts" setup>
import Card from '../component/Card.vue';
import { message } from 'jetlinks-ui-components';
import {
getModule,
licenseInit,
initPage,
getLicense,
} from '@/api/system/license';
let info = ref();
let license = ref();
let licenseTime = ref();
const saveData = (data: any) => {
if (data) {
save(data);
} else {
message.error('请配置License');
}
};
const getlicense = async () => {
const res: any = await getLicense();
if (res.status === 200) {
licenseTime.value = res.result;
license.value = res.result?.license;
}
};
const getInfo = async () => {
const res = await getModule();
if (res.status === 200) {
info.value = res.result;
}
};
const save = async (data: any) => {
const res: any = await licenseInit(data);
if (res.status === 200) {
message.success('配置成功');
const resp: any = await initPage();
if (resp.status === 200 && !resp.result.length) {
window.location.href = '/#/init-home';
} else {
window.location.href = '/';
}
}
};
onMounted(() => {
getInfo();
getlicense();
});
</script>
<style lang="less" scoped>
</style>

View File

@ -40,6 +40,7 @@
<j-input
v-model:value="form.data.name"
:disabled="props.mode === '查看'"
placeholder="请输入名称"
/>
</j-form-item>
<j-form-item
@ -92,7 +93,6 @@ const props = defineProps<{
const loading = ref(false);
const confirm = () => {
loading.value = true;
formRef.value &&
formRef.value.validate().then(() => {
const buttons = toRaw(props.menuInfo?.buttons) || [];
@ -108,6 +108,7 @@ const confirm = () => {
...props.menuInfo,
buttons,
};
loading.value = true;
saveMenuInfo_api(params)
.then((resp) => {
message.success('操作成功');

View File

@ -131,7 +131,6 @@ const permission = reactive({
const newProp = props.value.filter(
(item) => item.permission !== row.id,
);
if (newValue.length === row.options.length) {
row.checkAll = true;
row.indeterminate = false;
@ -146,6 +145,8 @@ const permission = reactive({
permission: row.id,
actions: newValue,
});
}else{
row.indeterminate = false
}
emits('update:value', newProp);

View File

@ -41,13 +41,13 @@
<template #action="slotProps">
<j-space :size="16">
<j-tooltip>
<template #title>查看</template>
<template #title>编辑</template>
<j-button
style="padding: 0"
type="link"
@click="table.toDetails(slotProps)"
>
<AIcon type="SearchOutlined" />
<AIcon type="EditOutlined" />
</j-button>
</j-tooltip>

View File

@ -57,7 +57,7 @@ const getTreeData = () => {
if (props.mode === 'api') {
tree[i].schemas = item.components.schemas;
tree[i].children = combData(item.paths);
} else if (i < values.length - 2) {
} else if (i < values.length - 1) {
const paths = filterPath(
item.paths,
values[values.length - 1].result as string[],

View File

@ -225,6 +225,8 @@ const defaultImg = getImage('/apply/provider1.png');
const iconMap = new Map();
iconMap.set('dingtalk-ent-app', getImage('/bind/dingtalk.png'));
iconMap.set('wechat-webapp', getImage('/bind/wechat-webapp.png'));
iconMap.set('internal-standalone', getImage('/apply/provider1.png'));
iconMap.set('third-party', getImage('/apply/provider5.png'));
const onFinish = async () => {
try {