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

This commit is contained in:
easy 2023-01-10 18:26:47 +08:00
commit c22c195200
26 changed files with 4906 additions and 1914 deletions

28
.commitlintrc.cjs Normal file
View File

@ -0,0 +1,28 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'build', // 编译相关修改(新版本发布)
'feat', // 新功能
'fix', // 修复bug
'update', // 更新某功能
'refactor', // 重构
'docs', // 文档
'chore', // 增加依赖或库
'style', // 格式(不影响代码变动)
'revert', // 撤销commit 回滚上一版本
'perf', // 性能优化
]
],
'type-case': [0],
'type-empty': [0],
'scope-empty': [0],
'scope-case': [0],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
'header-max-length': [0, 'always', 72]
}
}

1
.gitignore vendored
View File

@ -11,7 +11,6 @@ node_modules
dist
dist-ssr
*.local
yarn.lock
components.d.ts
# Editor directories and files

4
.husky/commit-msg Normal file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit ${1}

40
components.d.ts vendored
View File

@ -1,40 +0,0 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
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']
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
ACol: typeof import('ant-design-vue/es')['Col']
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
ADivider: typeof import('ant-design-vue/es')['Divider']
AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem']
AInput: typeof import('ant-design-vue/es')['Input']
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']
ASelect: typeof import('ant-design-vue/es')['Select']
ASpin: typeof import('ant-design-vue/es')['Spin']
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
ATree: typeof import('ant-design-vue/es')['Tree']
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']
TitleComponent: typeof import('./src/components/TitleComponent/index.vue')['default']
ValueItem: typeof import('./src/components/ValueItem/index.vue')['default']
}
}

View File

@ -8,15 +8,18 @@
"build": "vite build --mode production",
"preview": "vite preview",
"eslint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
"prettier": "prettier --write"
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
"prettier": "prettier --write",
"prepare": "husky install"
},
"dependencies": {
"@vitejs/plugin-vue-jsx": "^3.0.0",
"@vuemap/vue-amap": "^1.1.20",
"ant-design-vue": "^3.2.15",
"axios": "^1.2.1",
"js-cookie": "^3.0.1",
"echarts": "^5.4.1",
"jetlinks-store": "^0.0.3",
"js-cookie": "^3.0.1",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"lodash-es": "^4.17.21",
@ -26,20 +29,35 @@
"unplugin-auto-import": "^0.12.1",
"unplugin-vue-components": "^0.22.12",
"vue": "^3.2.45",
"vue-router": "^4.1.6",
"jetlinks-store": "^0.0.3"
"vue-router": "^4.1.6"
},
"devDependencies": {
"@commitlint/cli": "^17.4.1",
"@commitlint/config-conventional": "^17.4.0",
"@types/lodash-es": "^4.17.6",
"@types/moment": "^2.13.0",
"@types/node": "^18.11.17",
"@vitejs/plugin-vue": "^4.0.0",
"@vuemap/unplugin-resolver": "^1.0.4",
"autoprefixer": "^10.4.13",
"commitlint": "^17.4.1",
"husky": "^8.0.0",
"lint-staged": "^13.1.0",
"mrm": "^4.1.13",
"prettier": "^2.8.1",
"typescript": "^4.9.3",
"vite": "^4.0.0",
"vite-plugin-html": "^3.2.0",
"vite-plugin-vue-setup-extend": "^0.4.0",
"vue-tsc": "^1.0.11"
},
"lint-staged": {
"**/*.{vue,js,jsx,ts,tsx}": [
"npm run lint",
"prettier --write"
],
"**/*.{html,css,less,md}": [
"prettier --write"
]
}
}

3
src/api/device.ts Normal file
View File

@ -0,0 +1,3 @@
import server from '@/utils/request'
export const deleteMetadata = (deviceId: string) => server.remove(`/device-instance/${deviceId}/metadata`)

View File

@ -0,0 +1,3 @@
import server from '@/utils/request'
export const save = (data) => server.post(`/network/certificate`, data)

View File

@ -0,0 +1,13 @@
<template>
<div class=''>
</div>
</template>
<script setup type='ts' name='FormBuilder'>
const data = reactive({})
</script>
<style scoped>
</style>

View File

@ -0,0 +1,3 @@
import FormBuilder from './FormBuilder.vue'
export default FormBuilder

View File

@ -0,0 +1,168 @@
<template>
<div class="jtable-body">
<div class="jtable-body-header">
<div class="jtable-body-header-left">
<slot name="headerTitle"></slot>
</div>
<div class="jtable-body-header-right">
<div class="jtable-setting-item" :class="[ModelEnum.CARD === model ? 'active' : '']" @click="modelChange(ModelEnum.CARD)">
<AppstoreOutlined />
</div>
<div class="jtable-setting-item" :class="[ModelEnum.TABLE === model ? 'active' : '']" @click="modelChange(ModelEnum.TABLE)">
<UnorderedListOutlined />
</div>
</div>
</div>
<div class="jtable-content">
<div v-if="model === ModelEnum.CARD" class="jtable-card">
<div
v-if="dataSource.length"
class="jtable-card-items"
:style="{gridTemplateColumns: `repeat(${column}, 1fr)`}"
>
<div
class="jtable-card-item"
v-for="(item, index) in dataSource"
:key="index"
>
<slot name="cardRender" :item="item" :index="index"></slot>
</div>
</div>
<div v-else>
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
</div>
</div>
<div v-else>
<a-table :columns="columns" :dataSource="dataSource" :pagination="false" />
</div>
</div>
<div class="jtable-pagination" v-if="dataSource.length">
<a-pagination
size="small"
:total="50"
:show-total="total => `第 ${1} - ${1} 条/总共 ${total} 条`"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { UnorderedListOutlined, AppstoreOutlined } from '@ant-design/icons-vue'
import type { TableProps } from 'ant-design-vue/es/table'
import { Empty } from 'ant-design-vue'
enum ModelEnum {
TABLE = 'TABLE',
CARD = 'CARD',
}
export declare type RequestData = {
code: string;
result: {
data: Record<string, any>[] | undefined;
pageIndex: number;
pageSize: number;
total: number;
};
status: number;
} & Record<string, any>;
interface JTableProps extends TableProps{
request: (params: Record<string, any> & {
pageSize: number;
pageIndex: number;
}) => Promise<Partial<RequestData>>;
cardBodyClass?: string;
columns: Record<string, any>[];
params: Record<string, any> & {
pageSize: number;
pageIndex: number;
}
}
// propsemit
const emit = defineEmits(["modelChange"]);
const props = withDefaults(defineProps<JTableProps>(), {
cardBodyClass: '',
request: undefined
})
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE
const model = ref<keyof typeof ModelEnum>(ModelEnum.CARD); //
const column = ref<number>(4);
const dataSource = ref<Record<string, any>[]>([])
console.log(props)
//
//
const modelChange = (type: keyof typeof ModelEnum) => {
model.value = type
}
//
const handleSearch = async (params1?: Record<string, any>) => {
const resp = await props.request({
pageSize: 10,
pageIndex: 1,
...params1
})
if(resp.status === 200){
dataSource.value = resp.result?.data || []
}
}
watchEffect(() => {
handleSearch(props.params)
})
</script>
<style lang="less" scoped>
.jtable-body {
width: 100%;
padding: 0 24px 24px;
background-color: white;
.jtable-body-header {
padding: 16px 0;
display: flex;
justify-content: space-between;
align-items: center;
.jtable-body-header-right {
display: flex;
gap: 8px;
.jtable-setting-item {
color: rgba(0, 0, 0, 0.75);
font-size: 16px;
cursor: pointer;
&:hover {
color: @primary-color-hover;
}
&.active {
color: @primary-color-active;
}
}
}
}
.jtable-content {
.jtable-card {
.jtable-card-items {
display: grid;
grid-gap: 26px;
// grid-template-columns: repeat(4, 1fr);
.jtable-card-item {
display: flex;
}
}
}
}
.jtable-pagination {
margin-top: 20px;
display: flex;
justify-content: flex-end;
// position: absolute;
// right: 24px;
// bottom: 24px;
}
}
</style>

View File

@ -1,7 +1,8 @@
import { UnorderedListOutlined, AppstoreOutlined } from '@ant-design/icons-vue'
import styles from './index.module.less'
import { Space, Pagination, Table, Empty } from 'ant-design-vue'
import { Pagination, Table, Empty } from 'ant-design-vue'
import type { TableProps } from 'ant-design-vue/es/table'
enum ModelEnum {
TABLE = 'TABLE',
CARD = 'CARD',
@ -17,18 +18,15 @@ export declare type RequestData = {
};
status: number;
} & Record<string, any>;
// interface ColumnType extends
interface JTableProps extends TableProps{
// columns?: ColumnsType<RecordType>;
request: (params: Record<string, any> & {
pageSize?: number;
pageIndex?: number;
pageSize: number;
pageIndex: number;
}) => Promise<Partial<RequestData>>;
cardBodyClass?: string;
cardBodyClass: string;
}
const JTable = defineComponent<JTableProps>({
name: 'JTable',
slots: [
@ -38,10 +36,15 @@ const JTable = defineComponent<JTableProps>({
emits: [
'modelChange', // 切换卡片和表格
],
setup(props: JTableProps, { slots, emit }){
props: {
cardBodyClass: '',
request: undefined,
columns: []
} as any,
setup(props ,{ slots, emit }){
const model = ref<keyof typeof ModelEnum>(ModelEnum.CARD); // 模式切换
const column = ref<number>(3);
console.log(props)
console.log(props.columns, props.request)
const dataSource = ref<any[]>([
{
key: '1',
@ -81,6 +84,8 @@ const JTable = defineComponent<JTableProps>({
},
])
// 请求数据
onMounted(() => {
})

View File

@ -1,14 +1,16 @@
import type { App } from 'vue'
import AIcon from './AIcon'
import PermissionButton from './PermissionButton/index.vue'
import JTable from './Table/index'
import JTable from './Table/index.vue'
import TitleComponent from "./TitleComponent/index.vue";
import Form from './Form'
export default {
install(app: App) {
app.component('AIcon', AIcon)
app.component('PermissionButton', PermissionButton)
app.component('JTable', JTable)
app.component('TitleComponent', TitleComponent)
.component('PermissionButton', PermissionButton)
.component('JTable', JTable)
.component('TitleComponent', TitleComponent)
.component('Form', Form)
}
}

View File

@ -10,7 +10,6 @@ const router = createRouter({
router.beforeEach((to, from, next) => {
const token = LocalStore.get(TOKEN_KEY)
next() // 测试用, 可删除
if (token) {
next()
} else {

View File

@ -29,7 +29,7 @@ export default [
component: () => import('@/views/demo/index.vue')
},
{
path: '/bind',
path: '/account/center/bind',
component: () => import('@/views/account/Center/bind/index.vue')
},
{
@ -38,7 +38,11 @@ export default [
},
{
path: '/table',
component: () => import('@/views/table/index.vue')
component: () => import('@/views/demo/table/index.vue')
},
{
path: '/form',
component: () => import('@/views/demo/Form.vue')
},
// end: 测试用, 可删除

View File

@ -1,240 +0,0 @@
/** 路由Code */
export enum MENUS_CODE {
'home' = 'home',
'Analysis/CPU' = 'Analysis/CPU',
'Analysis/DeviceChart' = 'Analysis/DeviceChart',
'Analysis/DeviceMessage' = 'Analysis/DeviceMessage',
'Analysis/Jvm' = 'Analysis/Jvm',
'Analysis/MessageChart' = 'Analysis/MessageChart',
'Analysis' = 'Analysis',
'cloud/Aliyun' = 'cloud/Aliyun',
'cloud/Ctwing' = 'cloud/Ctwing',
'cloud/DuerOS' = 'cloud/DuerOS',
'cloud/Onenet' = 'cloud/Onenet',
'device/Alarm' = 'device/Alarm',
'device/Category/Save' = 'device/Category/Save',
'device/Category' = 'device/Category',
'device/Command' = 'device/Command',
'device/DataSource' = 'device/DataSource',
'device/Instance' = 'device/Instance',
'device/Location' = 'device/Location',
'device/Product/Save' = 'device/Product/Save',
'device/Product' = 'device/Product',
'device/DashBoard' = 'device/DashBoard',
'device/components/Alarm/Edit' = 'device/components/Alarm/Edit',
'device/components/Alarm/Record' = 'device/components/Alarm/Record',
'device/components/Alarm/Setting' = 'device/components/Alarm/Setting',
'device/components/Alarm' = 'device/components/Alarm',
'device/components/Metadata/Base/Edit' = 'device/components/Metadata/Base/Edit',
'device/components/Metadata/Base' = 'device/components/Metadata/Base',
'device/components/Metadata/Cat' = 'device/components/Metadata/Cat',
'device/components/Metadata/Import' = 'device/components/Metadata/Import',
'device/components/Metadata' = 'device/components/Metadata',
'link/Certificate' = 'link/Certificate',
'link/Certificate/Detail' = 'link/Certificate/Detail',
'link/Gateway' = 'link/Gateway',
'link/Protocol/Debug' = 'link/Protocol/Debug',
'link/Protocol' = 'link/Protocol',
'link/Type' = 'link/Type',
'link/AccessConfig' = 'link/AccessConfig',
'link/DataCollect/Dashboard' = 'link/DataCollect/Dashboard',
'link/DataCollect/DataGathering' = 'link/DataCollect/DataGathering',
'link/DataCollect/IntegratedQuery' = 'link/DataCollect/IntegratedQuery',
'edge/Device' = 'edge/Device',
'edge/Resource' = 'edge/Resource',
'Log' = 'Log',
'media/Cascade' = 'media/Cascade',
'media/Cascade/Save' = 'media/Cascade/Save',
'media/Cascade/Channel' = 'media/Cascade/Channel',
'media/Config' = 'media/Config',
'media/Device' = 'media/Device',
'media/Device/Save' = 'media/Device/Save',
'media/Device/Channel' = 'media/Device/Channel',
'media/Device/Playback' = 'media/Device/Playback',
'media/Reveal' = 'media/Reveal',
'media/Stream' = 'media/Stream',
'media/Stream/Detail' = 'media/Stream/Detail',
'media/DashBoard' = 'media/DashBoard',
'notice/Type' = 'notice/Type',
'notice/Config' = 'notice/Config',
'media/SplitScreen' = 'media/SplitScreen',
'notice/Type/Config' = 'notice/Config',
'notice/Config/Detail' = 'notice/Config/Detail',
'notice/Template' = 'notice/Template',
'notice/Template/Detail' = 'notice/Template/Detail',
'rule-engine/DashBoard' = 'rule-engine/DashBoard',
'rule-engine/Instance' = 'rule-engine/Instance',
'rule-engine/SQLRule' = 'rule-engine/SQLRule',
'rule-engine/Scene' = 'rule-engine/Scene',
'rule-engine/Alarm/Log' = 'rule-engine/Alarm/Log',
'rule-engine/Alarm/Log/Detail' = 'rule-engine/Alarm/Log/Detail',
'rule-engine/Alarm/Config' = 'rule-engine/Alarm/Config',
'rule-engine/Scene/Save' = 'rule-engine/Scene/Save',
'rule-engine/Scene/Save2' = 'rule-engine/Scene/Save2',
'rule-engine/Alarm/Configuration' = 'rule-engine/Alarm/Configuration',
'rule-engine/Alarm/Configuration/Save' = 'rule-engine/Alarm/Configuration/Save',
'simulator/Device' = 'simulator/Device',
'system/DataSource' = 'system/DataSource',
'system/DataSource/Management' = 'system/DataSource/Management',
'system/Department/Assets' = 'system/Department/Assets',
'system/Department/Member' = 'system/Department/Member',
'system/Department' = 'system/Department',
'system/Menu' = 'system/Menu',
'system/Menu/Setting' = 'system/Menu/Setting',
'system/OpenAPI' = 'system/OpenAPI',
'system/Permission' = 'system/Permission',
'system/Role/Detail' = 'system/Role/Detail',
'system/Role' = 'system/Role',
'system/Tenant/Detail/Assets' = 'system/Tenant/Detail/Assets',
'system/Tenant/Detail/Info' = 'system/Tenant/Detail/Info',
'system/Tenant/Detail/Member' = 'system/Tenant/Detail/Member',
'system/Tenant/Detail/Permission' = 'system/Tenant/Detail/Permission',
'system/Tenant/Detail' = 'system/Tenant/Detail',
'system/Tenant' = 'system/Tenant',
'system/User' = 'system/User',
'system/Relationship' = 'system/Relationship',
'system/Basis' = 'system/Basis',
'user/Login' = 'user/Login',
'visualization/Category' = 'visualization/Category',
'visualization/Configuration' = 'visualization/Configuration',
'visualization/Screen' = 'visualization/Screen',
'device/Firmware' = 'device/Firmware',
'device/Firmware/Task' = 'device/Firmware/Task',
'device/Firmware/Task/Detail' = 'device/Firmware/Task/Detail',
'device/Instance/Detail/Config/Tags' = 'device/Instance/Detail/Config/Tags',
'device/Instance/Detail/Config' = 'device/Instance/Detail/Config',
'device/Instance/Detail/Functions' = 'device/Instance/Detail/Functions',
'device/Instance/Detail/Info' = 'device/Instance/Detail/Info',
'device/Instance/Detail/Log' = 'device/Instance/Detail/Log',
'device/Instance/Detail/MetadataLog/Event' = 'device/Instance/Detail/MetadataLog/Event',
'device/Instance/Detail/MetadataLog/Property' = 'device/Instance/Detail/MetadataLog/Property',
'device/Instance/Detail/Running' = 'device/Instance/Detail/Running',
'device/Instance/Detail' = 'device/Instance/Detail',
'device/Product/Detail/BaseInfo' = 'device/Product/Detail/BaseInfo',
'device/Product/Detail' = 'device/Product/Detail',
'link/AccessConfig/Detail' = 'link/AccessConfig/Detail',
'link/DashBoard' = 'link/DashBoard',
'system/Menu/Detail' = 'system/Menu/Detail',
'system/Department/Detail' = 'system/Department/Detail',
'link/Type/Detail' = 'link/Type/Detail',
'account/Center' = 'account/Center',
'account/NotificationSubscription' = 'account/NotificationSubscription',
'account/NotificationRecord' = 'account/NotificationRecord',
'account/Center/bind' = 'account/Center/bind',
'Northbound/DuerOS' = 'Northbound/DuerOS',
'Northbound/DuerOS/Detail' = 'Northbound/DuerOS/Detail',
'Northbound/AliCloud' = 'Northbound/AliCloud',
'Northbound/AliCloud/Detail' = 'Northbound/AliCloud/Detail',
'system/Platforms' = 'system/Platforms',
'system/Platforms/Api' = 'system/Platforms/Api',
'system/Platforms/View' = 'system/Platforms/View',
'system/Platforms/Setting' = 'system/Platforms/Setting',
'system/Apply' = 'system/Apply',
'system/Apply/Api' = 'system/Apply/Api',
'system/Apply/View' = 'system/Apply/View',
'system/License' = 'system/License',
'iot-card/Home' = 'iot-card/Home',
'iot-card/Platform' = 'iot-card/Platform',
'iot-card/Platform/Detail' = 'iot-card/Platform/Detail',
'iot-card/Recharge' = 'iot-card/Recharge',
'iot-card/Dashboard' = 'iot-card/Dashboard',
'iot-card/CardManagement' = 'iot-card/CardManagement',
'iot-card/Record' = 'iot-card/Record',
}
export type MENUS_CODE_TYPE = keyof typeof MENUS_CODE | string;
export enum BUTTON_PERMISSION_ENUM {
'add' = 'add',
'delete' = 'delete',
'import' = 'import',
'view' = 'view',
'export' = 'export',
'update' = 'update',
'action' = 'action',
'push' = 'push',
'assert' = 'assert',
'bind-user' = 'bind-user',
'active' = 'active',
'sync' = 'sync',
'channel' = 'channel',
'debug' = 'debug',
'log' = 'log',
'tigger' = 'tigger',
'empowerment' = 'empowerment',
'bind' = 'bind',
'edit' = 'edit', //资产权限编辑
'setting' = 'setting', //菜单配置
'password' = 'password', //重置密码
'api' = 'api', //查看api
'manage' = 'manage', //数据源-管理
'stop' = 'stop',
'restart' = 'restart',
'pay' = 'pay', //充值
}
// 调试按钮、通知记录、批量导出、批量导入、选择通道、推送、分配资产、绑定用户对应的ID是啥
export type CUSTOM_BUTTON = 'debug' | 'log' | 'channel' | 'assert' | 'bind-user';
export type BUTTON_PERMISSION = keyof typeof BUTTON_PERMISSION_ENUM | string | CUSTOM_BUTTON;
export const getDetailNameByCode = {
'system/Menu/Detail': '菜单详情',
'device/Product/Detail': '产品详情',
'device/Instance/Detail': '设备详情',
'device/Firmware/Task/Detail': '详情',
'system/Department/Detail': '组织详情',
'system/Role/Detail': '权限配置',
'link/Type/Detail': '网络组件详情',
'link/AccessConfig/Detail': '配置详情',
'media/Stream/Detail': '流媒体详情',
'rule-engine/Alarm/Log/Detail': '告警日志',
'Northbound/AliCloud/Detail': '阿里云详情',
'link/Certificate/Detail': '证书详情',
'iot-card/Platform/Detail': '平台对接详情',
};
// 开源版路由
export const CommunityCodeList = [
'account/Center',
'account/NotificationSubscription',
'account/NotificationRecord',
'system/Basis',
'system/User',
'system/Department',
'system/Department/Detail',
'system/Role',
'system/Role/Detail',
'system/Menu',
'system/Menu/Detail',
'system/Menu/Setting',
'system/Permission',
'system/Relationship',
'home',
'rule-engine/DashBoard',
'rule-engine/Alarm/Configuration',
'rule-engine/Alarm/Configuration/Save',
'rule-engine/Alarm/Log',
'rule-engine/Alarm/Log/Detail',
'device/DashBoard',
'device/Category',
'device/Instance',
'device/Instance/Detail',
'device/Product',
'device/Product/Detail',
'link/AccessConfig',
'link/AccessConfig/Detail',
'link/Protocol',
'link/DashBoard',
'Log',
'link/Type',
'link/Type/Detail',
'link/Certificate',
'link/Certificate/Detail',
'rule-engine/Scene',
'rule-engine/Scene/Save',
'notice/Config',
'notice/Config/Detail',
'notice/Template',
'notice/Template/Detail',
];

View File

@ -1,10 +1,9 @@
import { defineStore } from "pinia";
import type { MENUS_CODE_TYPE, BUTTON_PERMISSION } from '@/router/router'
export const usePermissionStore = defineStore({
id: 'permission',
state: () => ({
permissions: {} as {[key: MENUS_CODE_TYPE]: BUTTON_PERMISSION},
permissions: {} as {[key: string]: string},
}),
getters: {
check(state) {

View File

@ -2,4 +2,6 @@ export const BASE_API_PATH = import.meta.env.VITE_APP_BASE_API
export const TOKEN_KEY = 'X-Access-Token'
export const Version_Code = 'version_code'
export const Version_Code = 'version_code'
export const NETWORK_CERTIFICATE_UPLOAD = '/network/certificate/upload'

View File

@ -171,6 +171,21 @@ const handleSubmit = () => {
console.log('error', err);
});
};
/**
* 绑定成功跳转至页面url的: redirect
*/
const goRedirect = () => {
const urlParams = new URLSearchParams(window.location.hash);
const redirectUrl =
urlParams.get('redirect') ||
window.location.href.split('redirect=')?.[1];
console.log('redirectUrl: ', redirectUrl);
//
if (redirectUrl && redirectUrl.indexOf('account/center/bind') === -1) {
window.location.href = decodeURIComponent(redirectUrl);
}
};
</script>
<style lang="less" scoped>

11
src/views/demo/Form.vue Normal file
View File

@ -0,0 +1,11 @@
<template>
<Form />
</template>
<script setup name='FormDemo'>
const data = reactive({})
</script>
<style scoped>
</style>

View File

@ -18,20 +18,27 @@
key: 'address',
}
]"
:request="request"
>
<template #headerTitle>
<a-button type="primary">新增</a-button>
</template>
<template #cardRender="slotProps">
{{slotProps.name}}
<CardBox>
<template #content>
{{slotProps.item.name}}
</template>
</CardBox>
</template>
</JTable>
</div>
</template>
<script setup lang="ts">
import { post } from "@/utils/request";
// :request="post('/device-product/_query', {})"
import server from "@/utils/request";
import CardBox from '@/components/CardBox/index.vue';
const request = (data: any) => server.post(`/device-product/_query`, data)
</script>

View File

@ -1,88 +1,91 @@
<template>
<a-spin :spinning="loading">
<div>
<a-textarea
:rows="4"
@change="textChange"
v-model="keystoreBase64"
:placeholder=placeholder
/>
<a-upload
accept=".pem"
listType="text"
:action="action"
:headers="headers"
:showUploadList="false"
@change="handleChange"
>
<a-button style="margin-top: 10px">
<upload-outlined></upload-outlined>
上传文件</a-button>
</a-upload>
</div>
</a-spin>
<a-spin :spinning="loading">
<div>
<a-textarea
:rows="4"
@change="textChange"
v-model:value="keystoreBase64"
:placeholder="placeholder"
/>
<a-upload
accept=".pem"
listType="text"
:action="`${BASE_API_PATH}${NETWORK_CERTIFICATE_UPLOAD}`"
:headers="{
[TOKEN_KEY]: LocalStore.get(TOKEN_KEY),
}"
:showUploadList="false"
@change="handleChange"
>
<a-button style="margin-top: 10px">
<upload-outlined />
上传文件</a-button
>
</a-upload>
</div>
</a-spin>
</template>
<script>
// import storage from 'store'
// import { ACCESS_TOKEN } from '@/store/mutation-types'
// import { ACCESS_TOKEN_KEY } from '@/utils/consts'
<script setup lang="ts" name="CertificateFile">
import { UploadOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import type { UploadChangeParam } from 'ant-design-vue';
import { LocalStore } from '@/utils/comm';
import {
BASE_API_PATH,
TOKEN_KEY,
NETWORK_CERTIFICATE_UPLOAD,
} from '@/utils/variable';
import type { UploadProps } from 'ant-design-vue';
export default {
name: 'CertificateFile',
data () {
return {
keystoreBase64: '',
loading: false,
action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
headers:{
authorization: 'authorization-text',
}
// action: process.env.VUE_APP_BASE_API + `/network/certificate/upload`,
// headers: {
// [ACCESS_TOKEN_KEY]: storage.get(ACCESS_TOKEN)
// }
}
},
model: {
prop: 'value',
event: 'change'
},
props: {
value: {
type: String,
default: () => ''
const emit = defineEmits(['update:modelValue', 'change']);
const props = defineProps({
name: {
type: String,
default: () => '',
},
modelValue: {
type: String,
default: () => '',
},
placeholder: {
type: String,
default: () => ''
}
},
watch: {
value: {
handler (v) {
this.keystoreBase64 = v
}
}
},
methods: {
handleChange (info) {
this.loading = true
if (info.file.status === 'done') {
this.$message.success('上传成功!')
const result = info.file.response?.result
this.loading = false
this.$emit('change', result)
}
type: String,
default: () => '',
},
textChange (val) {
this.$emit('change', val)
});
const keystoreBase64 = ref(props.modelValue);
const loading = ref(false);
const handleChange = (info: UploadChangeParam) => {
loading.value = true;
if (info.file.status === 'done') {
message.success('上传成功!');
const result = info.file.response?.result;
keystoreBase64.value = result;
console.log(1114, result);
loading.value = false;
emit('change', result);
emit('update:modelValue', result);
}
}
}
};
const textChange = (val: any) => {
val.name = props.name;
emit('change', val);
// emit('update:modelValue', val);
};
watch(
() => props.modelValue,
(v) => {
keystoreBase64.value = v;
},
{
deep: true,
immediate: true,
},
);
</script>
<style lang="less" scoped>
</style>
<style lang="less" scoped></style>

View File

@ -11,18 +11,9 @@
:wrapper-col="{ span: 16 }"
autocomplete="off"
@finish="onFinish"
@finishFailed="onFinishFailed"
:rules="formRules"
>
<a-form-item
label="证书标准"
name="type"
:rules="[
{
required: true,
message: '请选择证书标准',
},
]"
>
<a-form-item label="证书标准" name="type">
<a-radio-group v-model:value="formData.type">
<a-radio-button
class="form-radio-button"
@ -33,46 +24,25 @@
</a-radio-group>
</a-form-item>
<a-form-item
label="证书名称"
name="name"
:rules="[
{
required: true,
message: '请输入证书名称',
},
]"
>
<a-form-item label="证书名称" name="name">
<a-input
placeholder="请输入证书名称"
v-model:value="formData.name"
/>
</a-form-item>
<a-form-item
label="证书文件"
name="cert"
:rules="[
{
required: true,
message: '上传证书文件',
},
]"
>
<a-form-item label="证书文件" name="cert">
<CertificateFile
name="cert"
v-model:modelValue="formData.cert"
@change="changeFileValue"
placeholder='证书格式以"-----BEGIN CERTIFICATE-----"开头,以"-----END CERTIFICATE-----"结尾"'
/>
</a-form-item>
<a-form-item
label="证书私钥"
name="key"
:rules="[
{
required: true,
message: '请上传证书私钥',
},
]"
>
<a-form-item label="证书私钥" name="key">
<CertificateFile
name="key"
v-model:modelValue="formData.key"
@change="changeFileValue"
placeholder='证书私钥格式以"-----BEGIN (RSA|EC) PRIVATE KEY-----"开头,以"-----END(RSA|EC) PRIVATE KEY-----"结尾。'
/>
</a-form-item>
@ -117,46 +87,73 @@
</a-row>
</a-card>
</template>
<!-- export const ACCESS_TOKEN_KEY = 'X-Access-Token' -->
<!-- export const ACCESS_TOKEN = 'device_token' -->
<script lang="ts" setup name="CertificateDetail">
import { message } from 'ant-design-vue';
import { getImage } from '@/utils/comm';
import CertificateFile from './CertificateFile.vue';
import type { UploadChangeParam } from 'ant-design-vue';
import { LocalStore } from '@/utils/comm';
import {
BASE_API_PATH,
TOKEN_KEY,
NETWORK_CERTIFICATE_UPLOAD,
} from '@/utils/variable';
import { save } from '@/api/link/certificate';
const loading = ref(false);
const formData = reactive({
type: 'common',
name: '',
configs: {
cert: '',
key: '',
},
cert: '',
key: '',
// configs: {
// cert: '',
// key: '',
// },
description: '',
});
const onFinish = (values: any) => {
console.log('Success:', values);
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
const formRules = {
type: [{ required: true, message: '请选择证书标准', trigger: 'blur' }],
name: [
{ required: true, message: '请输入证书名称', trigger: 'blur' },
{ max: 64, message: '最多可输入64个字符' },
],
cert: [{ required: true, message: '请输入或上传文件', trigger: 'blur' }],
key: [{ required: true, message: '请输入或上传文件', trigger: 'blur' }],
description: [{ max: 200, message: '最多可输入200个字符' }],
};
const headers = {
authorization: 'authorization-text',
const onFinish = async (values: any) => {
values.configs = {
cert: formData.cert,
key: formData.key,
};
delete values.cert;
delete values.key;
const response = await save(values)
if (response.status === 200) {
message.success('操作成功')
}
};
const handleChange = (info: any) => {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}
const changeFileValue = (v: any) => {
formData[v.name] = v.data;
};
const handleChange = (info: UploadChangeParam) => {
loading.value = true;
if (info.file.status === 'done') {
message.success(`${info.file.name} file uploaded successfully`);
} else if (info.file.status === 'error') {
message.error(`${info.file.name} file upload failed.`);
message.success('上传成功!');
const result = info.file.response?.result;
formData.cert = result;
loading.value = false;
}
};
const fileList = ref([]);
</script>
<style lang="less" scoped>

View File

@ -18,8 +18,9 @@
"paths": {
"@/*": ["./src/*"]
},
"types": ["ant-design-vue/typings/global"]
"types": ["ant-design-vue/typings/global"],
"suppressImplicitAnyIndexErrors": true
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
"references": [{ "path": "./tsconfig.node.json" }],
}

View File

@ -7,6 +7,7 @@ import AutoImport from 'unplugin-auto-import/vite'
import { createHtmlPlugin } from 'vite-plugin-html'
import Config from './config/config'
import {VueAmapResolver} from '@vuemap/unplugin-resolver'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
import * as path from 'path'
@ -67,7 +68,8 @@ export default defineConfig(({ mode}) => {
favicon: `<link rel="icon" type="image/svg+xml" href="${Config.logo}" />`
}
}
})
}),
VueSetupExtend()
],
server: {
host:'0.0.0.0',

5916
yarn.lock

File diff suppressed because it is too large Load Diff