Merge branch 'dev' into dev-hub
This commit is contained in:
commit
bd267b32ff
|
@ -7,22 +7,28 @@ export {}
|
|||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
ABadge: typeof import('ant-design-vue/es')['Badge']
|
||||
AButton: typeof import('ant-design-vue/es')['Button']
|
||||
ACard: typeof import('ant-design-vue/es')['Card']
|
||||
ACol: typeof import('ant-design-vue/es')['Col']
|
||||
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
|
||||
AForm: typeof import('ant-design-vue/es')['Form']
|
||||
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||
AInput: typeof import('ant-design-vue/es')['Input']
|
||||
ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
|
||||
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
||||
AInputGroup: typeof import('ant-design-vue/es')['InputGroup']
|
||||
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
|
||||
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
||||
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
||||
ARow: typeof import('ant-design-vue/es')['Row']
|
||||
ASpin: typeof import('ant-design-vue/es')['Spin']
|
||||
ATextarea: typeof import('ant-design-vue/es')['Textarea']
|
||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
||||
AUpload: typeof import('ant-design-vue/es')['Upload']
|
||||
BadgeStatus: typeof import('./src/components/BadgeStatus/index.vue')['default']
|
||||
CardBox: typeof import('./src/components/CardBox/index.vue')['default']
|
||||
GeoComponent: typeof import('./src/components/GeoComponent/index.vue')['default']
|
||||
MonacoEditor: typeof import('./src/components/MonacoEditor/index.vue')['default']
|
||||
PermissionButton: typeof import('./src/components/PermissionButton/index.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
ValueItem: typeof import('./src/components/ValueItem/index.vue')['default']
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,7 @@
|
|||
"@vuemap/vue-amap": "^1.1.20",
|
||||
"ant-design-vue": "^3.2.15",
|
||||
"axios": "^1.2.1",
|
||||
"echarts": "^5.4.1",
|
||||
"less": "^4.1.3",
|
||||
"less-loader": "^11.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
|
@ -24,7 +25,8 @@
|
|||
"unplugin-auto-import": "^0.12.1",
|
||||
"unplugin-vue-components": "^0.22.12",
|
||||
"vue": "^3.2.45",
|
||||
"vue-router": "^4.1.6"
|
||||
"vue-router": "^4.1.6",
|
||||
"jetlinks-store": "^0.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 551 KiB |
|
@ -0,0 +1,3 @@
|
|||
<svg width="18" height="15" viewBox="0 0 18 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 1.12527V13.5414C0 14.2185 0.476821 14.6667 1.20199 14.6667H16.798C17.5132 14.6667 18 14.2185 18 13.5414V1.12527C18 0.448201 17.5232 0 16.798 0H1.20199C0.486755 0 0 0.448201 0 1.12527ZM1.20199 1.12527H16.798V4.51062H1.20199V1.12527ZM16.798 13.5414H1.20199V10.156H16.798V13.5414ZM1.20199 9.03077V5.63589H16.798V9.02124L1.20199 9.03077ZM13.798 2.25054H15C15.3576 2.25054 15.596 2.47941 15.596 2.81318C15.596 3.15648 15.3576 3.37581 15 3.37581H13.798C13.4404 3.37581 13.202 3.14694 13.202 2.81318C13.202 2.47941 13.4404 2.25054 13.798 2.25054ZM15.596 7.33333C15.596 7.67664 15.3576 7.89597 15 7.89597H13.798C13.4404 7.89597 13.202 7.6671 13.202 7.33333C13.202 6.99957 13.4404 6.7707 13.798 6.7707H15C15.3576 6.7707 15.596 6.99003 15.596 7.33333ZM13.202 11.844C13.202 11.5006 13.4404 11.2813 13.798 11.2813H15C15.3576 11.2813 15.596 11.5102 15.596 11.844C15.596 12.1873 15.3576 12.4066 15 12.4066H13.798C13.4404 12.4161 13.202 12.1873 13.202 11.844Z" fill="#597EF7"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,3 @@
|
|||
<svg width="12" height="16" viewBox="0 0 12 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.49722 15.875C3.66823 15.875 4.61944 14.9238 4.61944 13.7528C4.61944 12.8205 4.01688 12.0285 3.17936 11.7424V4.39228C4.01688 4.10616 4.61944 3.31412 4.61944 2.38186C4.61944 1.21085 3.66823 0.259636 2.49722 0.259636C1.32621 0.259636 0.375 1.21085 0.375 2.38186C0.375 3.31412 0.977559 4.10805 1.81508 4.39228V11.7424C0.977559 12.0285 0.375 12.8205 0.375 13.7528C0.375 14.9238 1.32621 15.875 2.49722 15.875ZM1.86055 14.384C1.69051 14.2174 1.59256 13.9908 1.5877 13.7528C1.59256 13.5148 1.69051 13.2882 1.86055 13.1216C2.03059 12.9549 2.25916 12.8616 2.49722 12.8616C2.73527 12.8616 2.96385 12.9549 3.13388 13.1216C3.30392 13.2882 3.40188 13.5148 3.40674 13.7528C3.40188 13.9908 3.30392 14.2174 3.13388 14.384C2.96385 14.5506 2.73527 14.6439 2.49722 14.6439C2.25916 14.6439 2.03059 14.5506 1.86055 14.384ZM3.13388 1.75252C3.30392 1.91913 3.40188 2.14574 3.40674 2.38375C3.40188 2.62176 3.30392 2.84838 3.13388 3.01498C2.96385 3.18158 2.73527 3.2749 2.49722 3.2749C2.25916 3.2749 2.03059 3.18158 1.86055 3.01498C1.69051 2.84838 1.59256 2.62176 1.5877 2.38375C1.59256 2.14574 1.69051 1.91913 1.86055 1.75252C2.03059 1.58592 2.25916 1.49261 2.49722 1.49261C2.73527 1.49261 2.96385 1.58592 3.13388 1.75252ZM11.3016 12.8713H9.84711V11.2344H9.84952V4.25811C10.687 3.97199 11.2896 3.17994 11.2896 2.24768C11.2896 1.07667 10.3384 0.125463 9.16738 0.125463C7.99637 0.125463 7.04516 1.07667 7.04516 2.24768C7.04516 3.17994 7.64772 3.97388 8.48524 4.25811V10.4632L8.48351 10.4633L8.48524 10.8587V11.2344H8.48688L8.49405 12.8734H7.04163C6.91267 12.8734 6.8429 13.0214 6.92113 13.1208L9.05219 15.8163C9.0663 15.8346 9.0844 15.8494 9.1051 15.8595C9.12581 15.8697 9.14857 15.875 9.17164 15.875C9.19471 15.875 9.21747 15.8697 9.23818 15.8595C9.25889 15.8494 9.27699 15.8346 9.29109 15.8163L11.4222 13.1187C11.5004 13.0193 11.4285 12.8713 11.3016 12.8713ZM10.0769 2.2485C10.072 2.0105 9.97405 1.78388 9.80401 1.61727C9.63397 1.45067 9.4054 1.35736 9.16735 1.35736C8.92929 1.35736 8.70072 1.45067 8.53068 1.61727C8.36064 1.78388 8.26268 2.0105 8.25782 2.2485C8.26268 2.48651 8.36064 2.71313 8.53068 2.87973C8.70072 3.04634 8.92929 3.13965 9.16735 3.13965C9.4054 3.13965 9.63397 3.04634 9.80401 2.87973C9.97405 2.71313 10.072 2.48651 10.0769 2.2485Z" fill="#597EF7"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -24,6 +24,10 @@ export default [
|
|||
path: '/demo',
|
||||
component: () => import('@/views/demo/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/bind',
|
||||
component: () => import('@/views/account/Center/bind/index.vue')
|
||||
},
|
||||
{
|
||||
path: '/iot/home',
|
||||
component: () => import('@/views/iot/home/index.vue')
|
||||
|
|
|
@ -28,3 +28,39 @@ export const StatusColorEnum = {
|
|||
'warning': 'warning',
|
||||
'default': 'default',
|
||||
}
|
||||
|
||||
class SystemConst {
|
||||
static API_BASE = 'api';
|
||||
|
||||
static SYSTEM_NAME = 'Jetlinks';
|
||||
|
||||
static LOGIN = 'LOGIN-STATUS';
|
||||
|
||||
static DOC_URL = 'http://doc.jetlinks.cn';
|
||||
|
||||
static BASE_CURD_MODAL_VISIBLE = 'BASE_CURD_MODAL_VISIBLE';
|
||||
|
||||
static BASE_CURD_CURRENT = 'BASE_CURD_CURRENT';
|
||||
|
||||
static BASE_CURD_MODEL = 'BASE_CURD_MODEL';
|
||||
|
||||
static BASE_UPDATE_DATA = 'BASE_UPDATE_DATA';
|
||||
|
||||
static GLOBAL_WEBSOCKET = 'GLOBAL-WEBSOCKET';
|
||||
|
||||
static BIND_USER_STATE = 'false';
|
||||
|
||||
static REFRESH_METADATA = 'refresh_metadata';
|
||||
|
||||
static REFRESH_METADATA_TABLE = 'refresh_metadata_table';
|
||||
|
||||
static GET_METADATA = 'get_metadata';
|
||||
|
||||
static REFRESH_DEVICE = 'refresh_device';
|
||||
|
||||
static AMAP_KEY = 'amap_key';
|
||||
|
||||
static Version_Code = 'version_code';
|
||||
}
|
||||
|
||||
export default SystemConst;
|
||||
|
|
|
@ -66,10 +66,10 @@ export const patch = function(url: string, data = {}) {
|
|||
* GET method request
|
||||
* @param {String} url
|
||||
* @param {Object} [params]
|
||||
* @param {Object} [ext], 扩展参数
|
||||
* @param {Object} [ext] 扩展参数
|
||||
* @returns {AxiosInstance}
|
||||
*/
|
||||
export const get = function(url: string, params = {}, ext: any) {
|
||||
export const get = function(url: string, params = {}, ext?: any) {
|
||||
return request({
|
||||
method: 'GET',
|
||||
url,
|
||||
|
@ -82,10 +82,10 @@ export const get = function(url: string, params = {}, ext: any) {
|
|||
* DELETE method request
|
||||
* @param {String} url
|
||||
* @param {Object} [params]
|
||||
* @param {Object} [ext], 扩展参数
|
||||
* @param {Object} [ext] 扩展参数
|
||||
* @returns {AxiosInstance}
|
||||
*/
|
||||
export const remove = function(url: string, params = {}, ext: any) {
|
||||
export const remove = function(url: string, params = {}, ext?: any) {
|
||||
return request({
|
||||
method: 'DELETE',
|
||||
url,
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
<!-- 第三方账户绑定 -->
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<div class="content">
|
||||
<div class="title">第三方账户绑定</div>
|
||||
<!-- 已登录-绑定三方账号 -->
|
||||
<template v-if="false">
|
||||
<div class="info">
|
||||
<a-card style="width: 280px">
|
||||
<template #title>
|
||||
<div class="info-head">
|
||||
<img :src="getImage('/bind/Rectangle.png')" />
|
||||
<span>个人信息</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="info-body">
|
||||
<img :src="getImage('/bind/jetlinksLogo.png')" />
|
||||
<p>账号:admin</p>
|
||||
<p>用户名:超级管理员</p>
|
||||
</div>
|
||||
</a-card>
|
||||
<img :src="getImage('/bind/Vector.png')" />
|
||||
<a-card style="width: 280px">
|
||||
<template #title>
|
||||
<div class="info-head">
|
||||
<img :src="getImage('/bind/Rectangle.png')" />
|
||||
<span>三方账户信息</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="info-body">
|
||||
<img :src="getImage('/bind/wechat-webapp.png')" />
|
||||
<p>用户名:-</p>
|
||||
<p>名称:微信昵称</p>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<a-button type="primary">立即绑定</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 未登录-绑定三方账号 -->
|
||||
<template v-else>
|
||||
<div class="not-login">
|
||||
<div class="logo">
|
||||
<img :src="getImage('/bind/jetlinksLogo.png')" />
|
||||
<img
|
||||
class="arrow"
|
||||
:src="getImage('/bind/Vector.png')"
|
||||
/>
|
||||
<img :src="getImage('/bind/wechat-webapp.png')" />
|
||||
</div>
|
||||
<div class="desc">
|
||||
你已通过微信授权,完善以下登录信息即可以完成绑定
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<a-form layout="vertical" :model="formData">
|
||||
<a-form-item label="账户">
|
||||
<a-input
|
||||
v-model:value="formData.username"
|
||||
placeholder="请输入账户"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input-password
|
||||
v-model:value="formData.password"
|
||||
placeholder="请输入密码"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="验证码">
|
||||
<a-input
|
||||
v-model:value="formData.captcha"
|
||||
placeholder="请输入验证码"
|
||||
>
|
||||
<template #addonAfter>图形验证码</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<a-button type="primary" style="width: 100%">
|
||||
登录并绑定账户
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getImage } from '@/utils/comm';
|
||||
|
||||
interface formData {
|
||||
username: string;
|
||||
password: string;
|
||||
captcha: string;
|
||||
}
|
||||
const formData = ref<formData>({
|
||||
username: '',
|
||||
password: '',
|
||||
captcha: '',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.page-container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background: url(/images/bind/bindPage.png) 0% 0% / 100% 100% no-repeat;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
width: 850px;
|
||||
min-height: 510px;
|
||||
background: #fff;
|
||||
border: 1px solid #e0e4e8;
|
||||
border-radius: 2px;
|
||||
.title {
|
||||
margin: 30px 0;
|
||||
color: #0f1222;
|
||||
font-weight: 400;
|
||||
font-size: 20px;
|
||||
font-family: 'PingFang SC';
|
||||
font-style: normal;
|
||||
line-height: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
// 已登录-绑定三方账号
|
||||
.info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
&-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 10px;
|
||||
}
|
||||
&-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
img {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
// 未登录
|
||||
.not-login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
.arrow {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
}
|
||||
.desc {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
font-size: 14px;
|
||||
font-family: 'PingFang SC';
|
||||
font-style: normal;
|
||||
line-height: 14px;
|
||||
opacity: 0.75;
|
||||
mix-blend-mode: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -2,7 +2,7 @@
|
|||
<template>
|
||||
<div class="page-container">
|
||||
父级: {{ testValue }}
|
||||
<ViewItem v-model="testValue" />
|
||||
<ValueItem v-model="testValue" />
|
||||
<!-- 卡片 -->
|
||||
<br />卡片组件:
|
||||
<a-row :gutter="20">
|
||||
|
@ -41,7 +41,6 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ViewItem from '@/components/ValueItem/index.vue';
|
||||
import CardBox from '@/components/CardBox/index.vue';
|
||||
import { StatusColorEnum } from '@/utils/consts';
|
||||
import { getImage } from '@/utils/comm';
|
||||
|
|
|
@ -13,20 +13,34 @@
|
|||
<div class="box-item">
|
||||
<div class="label">CPU使用率</div>
|
||||
<div class="value">{{ cpu }}</div>
|
||||
<div class="chart" ref="cpuChart"></div>
|
||||
<Pie
|
||||
class="chart"
|
||||
chart-ref="cpuChart"
|
||||
:value="20"
|
||||
:color-arr="['#ebebeb', '#d3adf7']"
|
||||
image="/images/home/top-3.svg"
|
||||
/>
|
||||
</div>
|
||||
<div class="box-item">
|
||||
<div class="label">JVM内存</div>
|
||||
<div class="value">{{ jvm }}</div>
|
||||
<div class="chart" ref="jvmChart"></div>
|
||||
<Pie
|
||||
class="chart"
|
||||
chart-ref="jvmChart"
|
||||
:value="31"
|
||||
:color-arr="['#d6e4ff', '#85a5ff']"
|
||||
image="/images/home/top-4.svg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const cpu = ref('0%');
|
||||
const jvm = ref('10%');
|
||||
import Pie from './Pie.vue';
|
||||
|
||||
const cpu = ref('20%');
|
||||
const jvm = ref('31%');
|
||||
|
||||
const jumpPage = () => {};
|
||||
</script>
|
||||
|
|
|
@ -6,12 +6,16 @@
|
|||
<div class="box">
|
||||
<div
|
||||
class="box-item"
|
||||
v-for="(item,index) in cardData"
|
||||
v-for="(item, index) in cardData"
|
||||
@click="jumpPage(item)"
|
||||
>
|
||||
<div class="item-english">{{ item.english }}</div>
|
||||
<div class="item-title">{{ item.label }}</div>
|
||||
<img class="item-image" :src="`/images/home/${index + 1}.png`" alt="" />
|
||||
<img
|
||||
class="item-image"
|
||||
:src="`/images/home/${index + 1}.png`"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
|
@ -25,7 +29,7 @@ type configItem = {
|
|||
link: string;
|
||||
english: string;
|
||||
label: string;
|
||||
save?: boolean;
|
||||
params?: object;
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
|
@ -35,13 +39,25 @@ const props = defineProps({
|
|||
});
|
||||
const { cardData, cardTitle } = toRefs(props);
|
||||
|
||||
const jumpPage = (linkItem: configItem): void => {
|
||||
if (linkItem.auth && linkItem.link) {
|
||||
router.push(`${linkItem.link}${linkItem.save ? '?save=true' : ''}`);
|
||||
const jumpPage = (row: configItem): void => {
|
||||
if (row.auth && row.link) {
|
||||
router.push(`${row.link}${objToParams(row.params || {})}`);
|
||||
} else {
|
||||
message.warning('暂无权限,请联系管理员');
|
||||
}
|
||||
};
|
||||
|
||||
const objToParams = (source: object): string => {
|
||||
if (Object.prototype.toString.call(source) === '[object Object]') {
|
||||
const paramsArr = <any>[];
|
||||
Object.entries(source).forEach(([prop, value]) => {
|
||||
if (typeof value === 'object') value = JSON.stringify(value);
|
||||
paramsArr.push(`${prop}=${value}`);
|
||||
});
|
||||
if (paramsArr.length > 0) return '?' + paramsArr.join('&');
|
||||
}
|
||||
return '';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
<template>
|
||||
<a-card class="boot-card-container" :bordered="false">
|
||||
<template #title>
|
||||
<h5 class="title">{{ cardTitle }}</h5>
|
||||
</template>
|
||||
<div class="box">
|
||||
<div
|
||||
class="box-item"
|
||||
v-for="(item, index) in cardData"
|
||||
@click="jumpPage(item)"
|
||||
>
|
||||
<div class="item-content">
|
||||
<div class="icon">
|
||||
<img :src="item.image" alt="" />
|
||||
</div>
|
||||
<div class="intro">
|
||||
<div class="item-english">{{ item.english }}</div>
|
||||
<div class="item-label">{{ item.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-bj">
|
||||
<img :src="`/images/home/home-${index + 1}.png`" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
type configItem = {
|
||||
auth: boolean;
|
||||
link: string;
|
||||
english: string;
|
||||
label: string;
|
||||
params?: object;
|
||||
image: string;
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
const props = defineProps({
|
||||
cardData: Array<configItem>,
|
||||
cardTitle: String,
|
||||
});
|
||||
const { cardData, cardTitle } = toRefs(props);
|
||||
|
||||
const jumpPage = (row: configItem): void => {
|
||||
if (row.auth && row.link) {
|
||||
router.push(`${row.link}${objToParams(row.params || {})}`);
|
||||
} else {
|
||||
message.warning('暂无权限,请联系管理员');
|
||||
}
|
||||
};
|
||||
|
||||
const objToParams = (source: object): string => {
|
||||
if (Object.prototype.toString.call(source) === '[object Object]') {
|
||||
const paramsArr = <any>[];
|
||||
// 直接使用for in遍历对象ts会报错
|
||||
Object.entries(source).forEach(([prop, value]) => {
|
||||
if (typeof value === 'object') value = JSON.stringify(value);
|
||||
paramsArr.push(`${prop}=${value}`);
|
||||
});
|
||||
if (paramsArr.length > 0) return '?' + paramsArr.join('&');
|
||||
}
|
||||
return '';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.boot-card-container {
|
||||
:deep(.ant-card-body) {
|
||||
padding-top: 0;
|
||||
}
|
||||
.title {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
padding-left: 18px;
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #1d39c4;
|
||||
border: 1px solid #b4c0da;
|
||||
transform: translateY(-50%);
|
||||
content: ' ';
|
||||
}
|
||||
}
|
||||
.box {
|
||||
font-size: 14px;
|
||||
.box-item {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
border-width: 1px 1px 1px 2px;
|
||||
border-style: solid;
|
||||
border-color: rgb(238, 238, 238) rgb(238, 238, 238)
|
||||
rgb(238, 238, 238) rgb(133, 165, 255);
|
||||
padding: 11px;
|
||||
background: linear-gradient(
|
||||
135.62deg,
|
||||
#f6f7fd 22.27%,
|
||||
rgba(255, 255, 255, 0.86) 91.82%
|
||||
);
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 4px 18px #efefef;
|
||||
&:not(:first-child) {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.item-label {
|
||||
color: #252526;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.right-bj {
|
||||
position: absolute;
|
||||
right: 10%;
|
||||
bottom: 0;
|
||||
width: 37px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,190 @@
|
|||
<template>
|
||||
<div class="comprehensive-home-conatiner">
|
||||
<a-row :gutter="24" class="top" style="margin-bottom: 24px">
|
||||
<a-col :span="6" class="left">
|
||||
<BootCardSmall
|
||||
:cardData="devBootConfig"
|
||||
cardTitle="物联网引导"
|
||||
/>
|
||||
<div style="width: 100%; height: 24px"></div>
|
||||
<BootCardSmall :cardData="opsBootConfig" cardTitle="运维引导" />
|
||||
</a-col>
|
||||
<a-col :span="18" class="right">
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="12"><DeviceCountCard /></a-col>
|
||||
<a-col :span="12"><BasicCountCard /></a-col>
|
||||
<a-col :span="24" style="margin-top: 24px">
|
||||
<PlatformPicCard image="/images/home/content1.png" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<StepCard
|
||||
cardTitle="设备接入推荐步骤"
|
||||
tooltip="不同的设备因为通信协议的不同,存在接入步骤的差异"
|
||||
:dataList="devStepDetails"
|
||||
style="margin-bottom: 24px"
|
||||
/>
|
||||
<StepCard
|
||||
cardTitle="运维管理推荐步骤"
|
||||
tooltip="请根据业务需要对下述步骤进行选择性操作。"
|
||||
:dataList="opsStepDetails"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="ComprehensiveHome">
|
||||
import BootCardSmall from '../BootCardSmall.vue';
|
||||
import DeviceCountCard from '../DeviceCountCard.vue';
|
||||
import BasicCountCard from '../BasicCountCard.vue';
|
||||
import PlatformPicCard from '../PlatformPicCard.vue';
|
||||
import { recommendList } from '../../index';
|
||||
|
||||
import StepCard from '../StepCard.vue';
|
||||
|
||||
// 物联网引导-数据
|
||||
const devBootConfig = [
|
||||
{
|
||||
english: 'STEP1',
|
||||
label: '创建产品',
|
||||
link: '/a',
|
||||
auth: true,
|
||||
save: true,
|
||||
image: '/images/home/guide-home1.png',
|
||||
},
|
||||
{
|
||||
english: 'STEP2',
|
||||
label: '创建设备',
|
||||
link: '/b',
|
||||
auth: true,
|
||||
save: true,
|
||||
image: '/images/home/guide-home2.png',
|
||||
},
|
||||
{
|
||||
english: 'STEP3',
|
||||
label: '规则引擎',
|
||||
link: '/c',
|
||||
auth: false,
|
||||
save: true,
|
||||
image: '/images/home/guide-home3.png',
|
||||
},
|
||||
];
|
||||
// 运维管理引导-数据
|
||||
const opsBootConfig = [
|
||||
{
|
||||
english: 'STEP1',
|
||||
label: '创建产品',
|
||||
link: '/a',
|
||||
auth: true,
|
||||
save: true,
|
||||
image: '/images/home/guide-home4.png',
|
||||
},
|
||||
{
|
||||
english: 'STEP2',
|
||||
label: '创建设备',
|
||||
link: '/b',
|
||||
auth: true,
|
||||
save: true,
|
||||
image: '/images/home/guide-home5.png',
|
||||
},
|
||||
{
|
||||
english: 'STEP3',
|
||||
label: '规则引擎',
|
||||
link: '/c',
|
||||
auth: false,
|
||||
save: true,
|
||||
image: '/images/home/guide-home6.png',
|
||||
},
|
||||
];
|
||||
// 设备接入推荐步骤-数据
|
||||
const devStepDetails = [
|
||||
{
|
||||
title: '创建产品',
|
||||
details:
|
||||
'产品是设备的集合,通常指一组具有相同功能的设备。物联设备必须通过产品进行接入方式配置。',
|
||||
iconUrl: '/images/home/bottom-4.png',
|
||||
linkUrl: '/a',
|
||||
auth: true,
|
||||
},
|
||||
{
|
||||
title: '配置产品接入方式',
|
||||
details:
|
||||
'通过产品对同一类型的设备进行统一的接入方式配置。请参照设备铭牌说明选择匹配的接入方式。',
|
||||
iconUrl: '/images/home/bottom-1.png',
|
||||
linkUrl: '/a',
|
||||
auth: true,
|
||||
dialogTag: 'accessMethod',
|
||||
},
|
||||
{
|
||||
title: '添加测试设备',
|
||||
details: '添加单个设备,用于验证产品模型是否配置正确。',
|
||||
iconUrl: '/images/home/bottom-5.png',
|
||||
linkUrl: '/a',
|
||||
auth: true,
|
||||
},
|
||||
{
|
||||
title: '功能调试',
|
||||
details:
|
||||
'对添加的测试设备进行功能调试,验证能否连接到平台,设备功能是否配置正确。',
|
||||
iconUrl: '/images/home/bottom-2.png',
|
||||
linkUrl: '/a',
|
||||
auth: true,
|
||||
dialogTag: 'funcTest',
|
||||
},
|
||||
{
|
||||
title: '批量添加设备',
|
||||
details: '批量添加同一产品下的设备',
|
||||
iconUrl: '/images/home/bottom-3.png',
|
||||
linkUrl: '/a',
|
||||
auth: false,
|
||||
},
|
||||
] as recommendList[];
|
||||
// 运维管理推荐步骤-数据
|
||||
const opsStepDetails = [
|
||||
{
|
||||
title: '协议管理',
|
||||
details:
|
||||
'根据业务需求自定义开发对应的产品(设备模型)接入协议,并上传到平台。',
|
||||
iconUrl: '/images/home/bottom-1.png',
|
||||
linkUrl: '/a',
|
||||
auth: true,
|
||||
params: {
|
||||
a: 1,
|
||||
save: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '证书管理',
|
||||
details: '统一维护平台内的证书,用于数据通信加密。',
|
||||
iconUrl: '/images/home/bottom-6.png',
|
||||
linkUrl: '/a',
|
||||
auth: true,
|
||||
params: {
|
||||
a: 1,
|
||||
save: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '网络组件',
|
||||
details: '根据不同的传输类型配置平台底层网络组件相关参数。',
|
||||
iconUrl: '/images/home/bottom-3.png',
|
||||
linkUrl: '/a',
|
||||
auth: true,
|
||||
},
|
||||
{
|
||||
title: '设备接入网关',
|
||||
details: '根据不同的传输类型,关联消息协议,配置设备接入网关相关参数。',
|
||||
iconUrl: '/images/home/bottom-4.png',
|
||||
linkUrl: '/a',
|
||||
auth: true,
|
||||
},
|
||||
{
|
||||
title: '日志管理',
|
||||
details: '监控系统日志,及时处理系统异常。',
|
||||
iconUrl: '/images/home/bottom-5.png',
|
||||
linkUrl: '/a',
|
||||
auth: false,
|
||||
},
|
||||
];
|
||||
</script>
|
|
@ -26,7 +26,6 @@ import BootCard from '../BootCard.vue';
|
|||
import DeviceCountCard from '../DeviceCountCard.vue';
|
||||
import PlatformPicCard from '../PlatformPicCard.vue';
|
||||
import StepCard from '../StepCard.vue';
|
||||
|
||||
// import {getImage} from '@/utils/comm'
|
||||
|
||||
// 物联网引导-数据
|
||||
|
@ -36,21 +35,21 @@ const bootConfig = [
|
|||
label: '创建产品',
|
||||
link: '/a',
|
||||
auth: true,
|
||||
save: true,
|
||||
params: {},
|
||||
},
|
||||
{
|
||||
english: 'STEP2',
|
||||
label: '创建设备',
|
||||
link: '/b',
|
||||
auth: true,
|
||||
save: true,
|
||||
params: {},
|
||||
},
|
||||
{
|
||||
english: 'STEP3',
|
||||
label: '规则引擎',
|
||||
link: '/c',
|
||||
auth: false,
|
||||
save: true,
|
||||
params: {},
|
||||
},
|
||||
];
|
||||
// 设备接入推荐步骤-数据
|
||||
|
|
|
@ -2,12 +2,43 @@
|
|||
<div class="init-home-container">
|
||||
<div class="title">请选择首页视图</div>
|
||||
|
||||
|
||||
|
||||
<div class="choose-view">
|
||||
<a-row class="view-content" :gutter="24">
|
||||
<a-col
|
||||
:span="8"
|
||||
class="select-item"
|
||||
:class="{ selected: selectId === '1' }"
|
||||
@click="selectId = '1'"
|
||||
>
|
||||
<img src="/images/home/device.png" alt="" />
|
||||
</a-col>
|
||||
<a-col
|
||||
:span="8"
|
||||
class="select-item"
|
||||
:class="{ selected: selectId === '2' }"
|
||||
@click="selectId = '2'"
|
||||
>
|
||||
<img src="/images/home/ops.png" alt="" />
|
||||
</a-col>
|
||||
<a-col
|
||||
:span="8"
|
||||
class="select-item"
|
||||
:class="{ selected: selectId === '3' }"
|
||||
@click="selectId = '3'"
|
||||
>
|
||||
<img src="/images/home/comprehensive.png" alt="" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-button type="primary" class="btn" @click="confirm">确定</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup></script>
|
||||
<script lang="ts" setup>
|
||||
const selectId = ref('1');
|
||||
|
||||
const confirm = ()=>{}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.init-home-container {
|
||||
|
@ -26,5 +57,29 @@
|
|||
font-size: 26px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.choose-view {
|
||||
width: 100%;
|
||||
.view-content {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
.select-item {
|
||||
border: 2px solid transparent;
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
border-color: #10239e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: block;
|
||||
margin: 48px auto;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<template>
|
||||
<div :ref="props.chartRef"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const props = defineProps({
|
||||
chartRef: String,
|
||||
value: Number,
|
||||
image: String,
|
||||
colorArr: Array<string>,
|
||||
});
|
||||
|
||||
const options = computed(() => ({
|
||||
color: props.colorArr || ['#D3ADF7', '#979AFF'],
|
||||
graphic: [
|
||||
{
|
||||
type: 'image',
|
||||
style: {
|
||||
image: props.image || '',
|
||||
width: 16,
|
||||
height: 16,
|
||||
},
|
||||
left: 'center',
|
||||
top: '41%',
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['100%', '60%'],
|
||||
center: ['50%', '50%'],
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
data: [100 - (props.value || 0), props.value],
|
||||
itemStyle: {
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2,
|
||||
},
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
watch(options, () => {
|
||||
initChart();
|
||||
});
|
||||
const initChart = () => {
|
||||
nextTick(() => {
|
||||
const myChart = echarts.init(proxy.$refs[props.chartRef]);
|
||||
|
||||
myChart.clear();
|
||||
myChart.setOption(options.value);
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
myChart.resize();
|
||||
});
|
||||
});
|
||||
};
|
||||
initChart();
|
||||
</script>
|
|
@ -4,11 +4,19 @@
|
|||
<span>平台架构图</span>
|
||||
<p>PLATFORM ARCHITECTURE DIAGRAM</p>
|
||||
</div>
|
||||
<img src="/images/home/content.png" class="bj" alt="" />
|
||||
<img
|
||||
:src="props.image || '/images/home/content.png'"
|
||||
class="bj"
|
||||
alt=""
|
||||
/>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
image: String,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ant-card-body) {
|
||||
|
@ -18,7 +26,7 @@
|
|||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
min-height: 480px;
|
||||
border-bottom: 1px solid #2f54eb;
|
||||
|
||||
.bj {
|
||||
display: block;
|
||||
|
@ -36,12 +44,12 @@
|
|||
padding: 24px 40px;
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
|
||||
p{
|
||||
|
||||
p {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
width: 100%;
|
||||
opacity: .3;
|
||||
opacity: 0.3;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,37 +23,54 @@
|
|||
<div class="box-details">{{ item.details }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialogs">
|
||||
<AccessMethodDialog :open-number="openAccess" />
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PropType } from 'vue';
|
||||
import { QuestionCircleOutlined } from '@ant-design/icons-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
interface listConfig {
|
||||
title: string;
|
||||
details: string;
|
||||
iconUrl: string;
|
||||
linkUrl: string;
|
||||
params?: object;
|
||||
auth: boolean;
|
||||
}
|
||||
import AccessMethodDialog from './dialogs/AccessMethodDialog.vue';
|
||||
|
||||
import { recommendList } from '../index';
|
||||
|
||||
const props = defineProps({
|
||||
cardTitle: String,
|
||||
tooltip: String,
|
||||
dataList: Array<listConfig>,
|
||||
dataList: Array as PropType<recommendList[]>,
|
||||
});
|
||||
const router = useRouter();
|
||||
|
||||
const { cardTitle, tooltip, dataList } = toRefs(props);
|
||||
const openAccess = ref<number>(0);
|
||||
const openFunc = ref<number>(0);
|
||||
|
||||
const jumpPage = (row: listConfig) => {
|
||||
if (row.auth && row.linkUrl) {
|
||||
router.push(`${row.linkUrl}${row.params ? '?save=true' : ''}`);
|
||||
} else {
|
||||
message.warning('暂无权限,请联系管理员');
|
||||
const jumpPage = (row: recommendList) => {
|
||||
if (!row.auth) return message.warning('暂无权限,请联系管理员');
|
||||
else if (row.dialogTag == 'accessMethod') return (openAccess.value += 1);
|
||||
else if (row.dialogTag === 'funcTest') return (openFunc.value += 1);
|
||||
else if (row.linkUrl) {
|
||||
router.push(`${row.linkUrl}${objToParams(row.params || {})}`);
|
||||
}
|
||||
};
|
||||
|
||||
const objToParams = (source: object): string => {
|
||||
if (Object.prototype.toString.call(source) === '[object Object]') {
|
||||
const paramsArr = <any>[];
|
||||
// 直接使用for in遍历对象ts会报错
|
||||
Object.entries(source).forEach(([prop, value]) => {
|
||||
if (typeof value === 'object') value = JSON.stringify(value);
|
||||
paramsArr.push(`${prop}=${value}`);
|
||||
});
|
||||
if (paramsArr.length > 0) return '?' + paramsArr.join('&');
|
||||
}
|
||||
return '';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
title="选择产品"
|
||||
style="width: 500px"
|
||||
@ok="handleOk"
|
||||
show-search
|
||||
:filter-option="filterOption"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="productId"
|
||||
style="width: 100%"
|
||||
:options="productList"
|
||||
>
|
||||
</a-select>
|
||||
<template #footer>
|
||||
<a-button key="back" @click="visible = false">取消</a-button>
|
||||
<a-button key="submit" type="primary" @click="handleOk"
|
||||
>确认</a-button
|
||||
>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { productItem } from '../../index';
|
||||
|
||||
const props = defineProps({
|
||||
openNumber: Number,
|
||||
});
|
||||
const emits = defineEmits(['confirm']);
|
||||
const { openNumber } = toRefs(props);
|
||||
const visible = ref<boolean>(false);
|
||||
|
||||
const productId = ref<string>('');
|
||||
const productList = ref<[productItem] | []>([]);
|
||||
|
||||
const getOptions = () => {
|
||||
productList.value = [];
|
||||
};
|
||||
const handleOk = () => {
|
||||
emits('confirm', productId.value);
|
||||
visible.value = false;
|
||||
};
|
||||
const filterOption = (input: string, option: any) => {
|
||||
return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
};
|
||||
watch(openNumber, () => {
|
||||
visible.value = true;
|
||||
productId.value = '';
|
||||
getOptions();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -0,0 +1,15 @@
|
|||
// 推荐步骤每项
|
||||
export interface recommendList {
|
||||
title: string;
|
||||
details: string;
|
||||
iconUrl: string;
|
||||
linkUrl: string;
|
||||
params?: object;
|
||||
auth: boolean;
|
||||
dialogTag?: 'accessMethod' | 'funcTest';
|
||||
}
|
||||
// 产品列表里的每项
|
||||
export interface productItem {
|
||||
label: string;
|
||||
value: string
|
||||
}
|
|
@ -4,7 +4,9 @@
|
|||
<div class="left"></div>
|
||||
<div class="content iot-home-container">
|
||||
<!-- <InitHome /> -->
|
||||
<DeviceHome />
|
||||
<!-- <DeviceHome /> -->
|
||||
<!-- <DevOpsHome /> -->
|
||||
<ComprehensiveHome />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -12,6 +14,9 @@
|
|||
<script lang="ts" setup>
|
||||
import InitHome from './components/InitHome/index.vue';
|
||||
import DeviceHome from './components/DeviceHome/index.vue';
|
||||
import DevOpsHome from './components/DevOpsHome/index.vue';
|
||||
import ComprehensiveHome from './components/ComprehensiveHome/index.vue';
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
@ -30,14 +35,12 @@ import DeviceHome from './components/DeviceHome/index.vue';
|
|||
background: #352d85;
|
||||
width: 210px;
|
||||
min-height: calc(100vh - 48px);
|
||||
|
||||
}
|
||||
.content {
|
||||
margin: 24px;
|
||||
width: calc(100vw - 258px);
|
||||
width: calc(100vw - 280px);
|
||||
overflow: hidden;
|
||||
min-height: calc(100vh - 96px);
|
||||
}
|
||||
}
|
||||
// .iot-home-container {
|
||||
// }
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue