Commit 35b748b4 by 周田

merge:合并之前的页面代码

parent 1bfdeecf
<template>
<div class="common-layout">
<el-container>
<el-header>
<el-menu :default-active="activeIndex" class="el-menu-demo pl-20" mode="horizontal">
<el-menu-item index="index">
<router-link to="/"> 首页 </router-link>
</el-menu-item>
<el-menu-item index="protocol">
<router-link to="/protocol"> 协议 </router-link>
</el-menu-item>
<el-menu-item index="communication">
<router-link to="/communication"> 通信参数 </router-link>
</el-menu-item>
</el-menu>
</el-header>
<el-main>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</el-main>
</el-container>
</div>
</template>
<script setup lang="ts"> <script setup lang="ts">
import Chat from '@/views/Chat' import { ref } from 'vue'
// import FileDown from './views/FileDown.vue'; const activeIndex = ref('1')
// import Upload from './views/Upload.vue';
// import Tabs from './views/Tabs.vue';
// import DeviceCommunication from '@/views/DeviceCommunication';
</script> </script>
<style>
<template> .el-header {
<chat /> --el-header-padding: 0 !important;
<!-- <FileDown /> --> }
<!-- <Upload /> --> </style>
<!-- <Tabs /> -->
<!-- <device-communication /> -->
</template>
<template>
<div class="chat-box">
<div class="message" ref="messageContainer">
<div v-for="(message, index) in props.messages" :key="index">
{{ message }}
<br /> <!-- 换行 -->
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
type propsType = {
messages: string
}
//使用父组件传递过来的值
const props = defineProps<propsType>()
const messageContainer = ref<HTMLDivElement>();
function scrollToBottom() {
messageContainer.value!.scrollTop = messageContainer.value!.scrollHeight;
}
watchEffect(() => {
// 在 messages 更新后滚动到底部
scrollToBottom();
});
</script>
<style scoped>
.chat-box {
width: 300px;
height: 400px;
border: 1px solid #ccc;
overflow-y: auto;
}
.message {
padding: 8px;
margin: 4px;
border-radius: 4px;
background-color: #f0f0f0;
}
</style>
<template>
<div class="demo-collapse">
<div class="container">
<div class="left">
<div class="mr-4">协议版本</div>
<el-select>
<el-option :value="option"></el-option>
</el-select>
</div>
<div class="right">
<el-button @click="addCmd = true">新增指令</el-button>
<el-button>导出协议</el-button>
</div>
</div>
<div class="mb-4 mt-4">协议规范</div>
<el-collapse class="mt-4">
<el-collapse-item v-for="cmd in props.info[props.name]" :title="cmd.cmd_name + ' ' + cmd.cmd_explain + ' ' + cmd.cmd_type">
<protpcol-table v-if="props.protocolcmd !== null" :info="cmd.cmd_name" :message="props.protocolcmd"
:type="cmd.cmd_type"></protpcol-table>
</el-collapse-item>
</el-collapse>
<el-dialog v-model="addCmd" title="新增指令">
<el-form>
<el-form-item label="协议名称" :label-width="formLabelWidth">
<el-input autocomplete="off" />
</el-form-item>
<el-form-item label="指令名称" :label-width="formLabelWidth">
<el-input autocomplete="off" />
</el-form-item>
<el-form-item label="指令类型" :label-width="formLabelWidth">
<el-select>
<el-option label="TX" value="TX"></el-option>
<el-option label="RX" value="RX"></el-option>
</el-select>
</el-form-item>
<el-form-item label="协议类型" :label-width="formLabelWidth">
<el-select>
<el-option label="ASCII" value="ASCII"></el-option>
<el-option label="HEX" value="HEX"></el-option>
</el-select>
</el-form-item>
<el-form-item label="定时发送" :label-width="formLabelWidth">
<el-input autocomplete="off" />
</el-form-item>
<el-form-item label="说明" :label-width="formLabelWidth">
<el-input autocomplete="off" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="addCmd = false">取消</el-button>
<el-button type="primary" @click="open">
确定
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from "element-plus";
import ProtpcolTable from "./protpcol-table.vue";
const addCmd = ref<boolean>(false)
const option = ref<string>('option')
const formLabelWidth = '140px'
type propsType = {
name: string,
info: Object,
protocolcmd: Object
}
const props = defineProps<propsType>()
// const item = ref()
// item.value = toRefs(props).name.value
// const parentMsg = ref()
// parentMsg.value = toRefs(props).info.value[item.value]
// const protocolCmd = ref()
// protocolCmd.value = toRefs(props).protocolcmd.value
const open = () => {
ElMessageBox.confirm(
'是否确认增加?',
'Warning',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
ElMessage({
type: 'success',
message: '增加成功',
})
addCmd.value = false
})
.catch(() => {
ElMessage({
type: 'info',
message: '已取消',
})
})
}
</script>
<style>
.container {
display: flex;
justify-content: space-between;
/* 使内部元素平均分布 */
align-items: center;
/* 垂直居中 */
margin: auto;
}
.left {
align-items: center;
display: flex;
}
.right {
display: flex;
align-items: center;
/* 垂直居中 */
}</style>
<template>
<div style="width: 95%;margin: auto">
<div class="flex mt-4 items-center">
<div>设备名称</div>
<div class="ml-4">tcp server</div>
<div class="ml-4">ip</div>
<div class="ml-4">port</div>
<el-switch v-model="value" :disabled="isSwitchDisabled" class="ml-4"></el-switch>
<el-button class="ml-4" @click="dialogFormVisible = true">设置</el-button>
</div>
<el-table
style="width: 100%"
:data="tableData"
:show-header="false" border
class="mt-2"
>
<el-table-column
v-for="(item, index) in tableHeader"
:key="index"
:prop="item"
:fixed="isTitleColumn ? 'left' : ''"
>
</el-table-column>
</el-table>
</div>
<el-dialog v-model="dialogFormVisible">
<el-form :model="form">
<el-form-item label="模式" :label-width="formLabelWidth">
<el-select v-model="form.mode">
<el-option label="tcp server" value="tcp server" />
<el-option label="tcp client" value="tcp client" />
<el-option label="tcp/ip" value="tcp/ip" />
<el-option label="udp" value="udp" />
</el-select>
</el-form-item>
<el-form-item label="ip" :label-width="formLabelWidth">
<el-input v-model="form.ip" autocomplete="off" />
</el-form-item>
<el-form-item label="端口" :label-width="formLabelWidth">
<el-input v-model="form.port" autocomplete="off" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogFormVisible = false">取消</el-button>
<el-button type="primary" @click="dialogFormVisible = false">
确定
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ElTableColumn } from 'element-plus';
import {ref, watch} from 'vue'
const value = ref(true)
const dialogFormVisible = ref(false)
const formLabelWidth = '140px'
const tableHeader = ref<string[]>([])
type Table = {
title: string,
value0: string,
value1: string,
value2: string
}
const tableData = ref<Table[]>([
{title:'变量', value0: '模式', value1: 'ip', value2: '端口'},
{title: '值', value0: 'tcp server', value1: 'localhost', value2: '8000'}
]
)
const form = ref(
{mode:'', ip: '', port: ''}
)
type propsType = {
tag:String
}
const props = defineProps<propsType>()
const isSwitchDisabled = ref(true)
watch( () => props.tag, (newValue) => {
if (newValue === 'real'){
value.value = true
isSwitchDisabled.value = true
}else if(newValue === 'virtual'){
isSwitchDisabled.value = false
}
})
const isTitleColumn = (column: any) => column.property === 'title'
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<div class="demo-collapse">
<el-collapse>
<el-collapse-item v-for="item in protocols" >
<template #title>{{item}}</template>
<div style="margin: auto; width: 90%">
<collapse-table
v-if="protocolcmd"
class="mt-4"
:info="parentMsg"
:name="item"
:protocolcmd="protocolcmd"
>
</collapse-table>
</div>
</el-collapse-item>
</el-collapse>
</div>
</template>
<script setup lang="ts">
import {ref, onMounted } from 'vue'
import CollapseTable from "./collapse-table.vue";
import { DeviceProtocol, ProtocolCmd } from "@/dao/device";
const protocols = ref()
const parentMsg = ref()
const protocolcmd = ref()
async function getDeviceProtocol(){
let data = await DeviceProtocol()
protocols.value = data.fields
parentMsg.value = data
}
async function getProtocolCmd(){
let cmds = await ProtocolCmd()
protocolcmd.value = cmds
}
onMounted(async () => {
await getDeviceProtocol()
await getProtocolCmd()
})
</script>
<style>
.el-collapse-item__header {
padding-left: 40px; /* 调整合适的左边距值 */
}
</style>
<template>
<DeviceTable v-if="tag" :tag="tag"></DeviceTable>
<div style="display: flex; justify-content: center;">
<el-button
class="mt-2" style="width: 95%;border: 1px dashed"
@click="open"
>+</el-button>
</div>
<el-dialog v-model="deviceVisible">
<el-form :model="device">
<el-form-item label="模式" :label-width="formLabelWidth">
<el-select v-model="device.mode">
<el-option label="tcp server" value="tcp server" />
<el-option label="tcp client" value="tcp client" />
<el-option label="tcp/ip" value="tcp/ip" />
<el-option label="udp" value="udp" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="deviceVisible = false">取消</el-button>
<el-button type="primary" @click="deviceVisible = false">
确定
</el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="virtualDeviceVisible">
<el-form :model="virtualDevice">
<el-form-item label="协议" :label-width="formLabelWidth">
<el-select v-model="virtualDevice.protocol">
<el-option label="option 1" value="option 1" />
</el-select>
</el-form-item>
<el-form-item label="协议版本" :label-width="formLabelWidth">
<el-select v-model="virtualDevice.version">
<el-option label="option 1" value="option 1" />
</el-select>
</el-form-item>
<el-form-item label="模式" :label-width="formLabelWidth">
<el-select v-model="virtualDevice.mode">
<el-option label="tcp server" value="tcp server" />
<el-option label="tcp client" value="tcp client" />
<el-option label="udp" value="udp" />
<el-option label="udp mc" value="udp mc" />
</el-select>
</el-form-item>
<el-form-item label="本机ip" :label-width="formLabelWidth" v-if="isTCP_client">
<el-input v-model="virtualDevice.HostIP" autocomplete="off" />
</el-form-item>
<el-form-item label="本机端口" :label-width="formLabelWidth" v-if="isTCP_client">
<el-input v-model="virtualDevice.HostPort" autocomplete="off" />
</el-form-item>
<el-form-item label="目标ip" :label-width="formLabelWidth" v-if="isUDP">
<el-input v-model="virtualDevice.DstIP" autocomplete="off" />
</el-form-item>
<el-form-item label="目标端口" :label-width="formLabelWidth" v-if="isUDP">
<el-input v-model="virtualDevice.DstPort" autocomplete="off" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="virtualDeviceVisible = false">取消</el-button>
<el-button type="primary" @click="virtualDeviceVisible = false">
确定
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import {ref, watch} from 'vue'
import DeviceTable from "./device-table.vue";
const deviceVisible = ref(false)
const virtualDeviceVisible = ref(false)
const formLabelWidth = '140px'
const isUDP = ref(false)
const isTCP_client = ref(true)
const device = ref<Record<string, string>>({mode: ''})
const virtualDevice = ref<Record<string, string>>(
{protocol: '', version: '', mode: '', HostIP: '', HostPort: '', DstIP: '', DstPort: ''}
)
type propsType = {
tag: string
}
const props = defineProps<propsType>()
const tag = ref(props.tag)
const open = () => {
isUDP.value = false
isTCP_client.value = true
if (props.tag === 'real'){
for (const key in device.value){
device.value[key] = ''
}
deviceVisible.value = true
}else {
for (const key in virtualDevice.value){
virtualDevice.value[key] = ''
}
virtualDeviceVisible.value = true
}
}
watch( () => props.tag, (newValue) => {
tag.value = newValue
})
watch( () => virtualDevice.value.mode, (newValue) => {
if (newValue === 'udp' || newValue === 'udp mc'){
isUDP.value = true
isTCP_client.value = true
}else if (newValue === 'tcp client'){
isUDP.value = true
isTCP_client.value = false
}else {
isUDP.value = false
isTCP_client.value = true
}
})
</script>
<style scoped>
</style>
\ No newline at end of file
<template>
<el-row >
<el-col >
<el-menu @select="handleMenuItemSelect">
<el-sub-menu index="1">
<template #title>
<span>设备列表</span>
</template>
<el-sub-menu index="1-1">
<template #title>
<span>ACU</span>
</template>
<el-menu-item index="/acu">
<span>7.5米ACU(23所)</span>
</el-menu-item>
<el-menu-item index="1-1-2">
<span>5米ACU(2=39所)</span>
</el-menu-item>
</el-sub-menu>
<el-menu-item index="1-2">
<span>变频器</span>
</el-menu-item>
<el-menu-item index="1-3">
<span>信号源</span>
</el-menu-item>
<el-menu-item index="1-4">
<span>跟踪接收机</span>
</el-menu-item>
<el-menu-item index="1-5">
<span>矩阵</span>
</el-menu-item>
<el-menu-item index="1-6">
<span>气象站</span>
</el-menu-item>
</el-sub-menu>
</el-menu>
</el-col>
</el-row>
</template>
<script setup lang="ts">
const emit = defineEmits(['handleMenuItemSelect'])
function handleMenuItemSelect(index: string){
emit('handleMenuItemSelect', index)
}
</script>
<template>
<el-table
:data="tableData"
style="width: 100%"
>
<el-table-column fixed prop="fieldname" label="字段名" style="width: 25%" />
<el-table-column prop="fieldsize" label="字段长度" style="width: 25%" />
<el-table-column prop="value" label="默认值" style="width: 25%" />
<el-table-column fixed="right" style="width: 25%">
<template #default="{row}">
<div style="display: flex;">
<el-button type="primary" @click="open('delete', row)">删除字段</el-button>
<el-button type="primary" @click="editField(row)">修改字段</el-button>
</div>
</template>
</el-table-column>
</el-table>
<el-button
style="width: 100%; border: 1px dashed"
class="mt-4"
@click="addField"
>+</el-button>
<el-dialog v-model="dialogVisible" @close="resetForm">
<template #title>{{flag ? '新增' : '编辑'}}字段</template>
<el-form
ref="ruleFormRef"
label-position="right"
label-width="150px"
:model="fields"
:rules="rules"
>
<el-row>
<el-col :span="12">
<el-form-item label="命令名">
<el-input v-model="fields.cmd_name" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="指令类型">
<el-input v-model="fields.cmd_type" disabled></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="序号">
<el-input v-model="fields.fieldindex" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="名称" prop="fieldname">
<el-input v-model="fields.fieldname"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="长度" prop="fieldsize">
<el-input v-model="fields.fieldsize"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="值" prop="value">
<el-input v-model="fields.value"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="指令最大值">
<el-input v-model="fields.maxvalue"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="指令最小值">
<el-input v-model="fields.minvalue"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="字段类型" prop="datatype">
<el-select v-model="fields.datatype">
<el-option v-for="item in fieldTypes" :label="item.label" :value="item.value" :key="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="Lua对输入数据的操作">
<el-input v-model="fields.lua_script_in"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="Lua对输出数据的操作">
<el-input v-model="fields.lua_script_out"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12" :offset="12">
<el-form-item >
<el-button class="mr-0" @click="more = !more">更多操作</el-button>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="more">
<el-col :span="12">
<el-form-item label="输入数据操作">
<el-input v-model="fields.operation_in"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="输入数据操作参数">
<el-input v-model="fields.operation_in_num"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="more">
<el-col :span="12">
<el-form-item label="输出数据操作">
<el-input v-model="fields.operation_out"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="输出数据操作参数">
<el-input v-model="fields.operation_out_num"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="more">
<el-col :span="12">
<el-form-item label="输入数据字节操作">
<el-input v-model="fields.operabo_in"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="输出数据字节操作">
<el-input v-model="fields.operabo_out"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="open">
确定
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import {ElMessage, ElMessageBox} from "element-plus";
import {AddProtocolCMd, DeleteProtocolCmd, EditProtocolCmd} from "@/dao/device";
const flag = ref(false)
const dialogVisible = ref(false)
const more = ref(false)
type propsType = {
info: string,
type: string,
message: Record<string, any>
}
const props = defineProps<propsType>()
const cmdName = props.info
const cmdFields = ref(props.message.value[cmdName])
const tableData = ref([])
const rules = ref({
fieldname: [
{required: true, message: "请输入名称", trigger: 'blur'}
],
fieldsize: [
{required: true, message: "请输入长度", trigger: 'blur'}
],
value: [
{required: true, message: "请输入值", trigger: 'blur'}
],
datatype: [
{required: true, message: "请选择字段类型", trigger: 'change'}
],
})
const ruleFormRef = ref()
for (const item of cmdFields.value){
tableData.value.push(item)
}
type fieldType = {
cmd_name: string,
cmd_type: string,
fieldindex: number,
fieldname: string,
fieldsize: string,
value: string,
minvalue: string,
maxvalue: string,
datatype: string,
operation_in: number,
operation_in_num: number,
operation_out: number,
operation_out_num: number,
operabo_in: number,
operabo_out: number,
lua_script_in: string,
lua_script_out: string
}
const fields = ref<fieldType>({
cmd_name: '',
cmd_type: '',
fieldindex: 0,
fieldname: '',
fieldsize: '',
value: '',
minvalue: '',
maxvalue: '',
datatype: '',
operation_in: 0,
operation_in_num: 0,
operation_out: 0,
operation_out_num: 0,
operabo_in: 0,
operabo_out: 0,
lua_script_in: '',
lua_script_out: ''
})
const fieldTypes = [
{ value: 0, label: 'DATATYPE_DEFAULT'},
{ value: 1, label: 'DATATYPE_STR '},
{ value: 2, label: 'DATATYPE_UINT_STR '},
{ value: 3, label: 'DATATYPE_INT_STR '},
{ value: 4, label: 'DATATYPE_FLOAT_STR '},
{ value: 5, label: 'DATATYPE_DOUBLE_STR '},
{ value: 6, label: 'DATATYPE_HEX '},
{ value: 7, label: 'DATATYPE_STR_HEX '},
{ value: 8, label: 'DATATYPE_UINT_HEX '},
{ value: 9, label: 'DATATYPE_INT_HEX '},
{ value: 10, label: 'DATATYPE_FLOAT_HEX '},
{ value: 11, label: 'DATATYPE_DOUBLE_HEX '},
{ value: 12, label: 'DATATYPE_DOUBLE '},
{ value: 13, label: 'DATATYPE_PAYLOAD '},
{ value: 14, label: 'DATATYPE_INT8 '},
{ value: 15, label: 'DATATYPE_TIMESTR '},
{ value: 16, label: 'DATATYPE_MAX'},
]
let operation = ''
const addField = () => {
flag.value = true;
more.value = false
// for(const key in fields.value){
// fields.value[key] = '';
// }
fields.value.cmd_name = props.info
fields.value.cmd_type = props.type
fields.value.fieldindex = tableData.value.length + 1
fields.value.minvalue = 'null'
fields.value.maxvalue = 'null'
fields.value.lua_script_in = 'null'
fields.value.lua_script_out = 'null'
fields.value.operation_in = 0
fields.value.operation_in_num = 0
fields.value.operation_out = 0
fields.value.operation_out_num = 0
fields.value.operabo_in = 0
fields.value.operabo_out = 0
dialogVisible.value = true;
if (ruleFormRef.value){
ruleFormRef.value.clearValidate()
}
}
function editField(data){
dialogVisible.value = true
flag.value = false
more.value = false
for (const key in data){
fields.value[key] = data[key]
}
}
const resetForm = () => {
for (const key in fields.value){
fields.value[key] = ''
}
ruleFormRef.value.clearValidate()
}
async function Edit(id, params){
await EditProtocolCmd(id, params)
}
async function Delete(id){
await DeleteProtocolCmd(id)
}
async function Add(params){
await AddProtocolCMd(params)
}
function confirm(str, data){
if (str === 'delete'){
operation = '删除'
} else if(flag.value){
operation = '增加'
}else if (!flag.value){
operation = '修改'
}
ElMessageBox.confirm(
'是否确认' + operation + '?',
'Warning',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
ElMessage({
type: 'success',
message: operation + '成功',
})
dialogVisible.value = false
more.value = false
if (operation === '修改'){
let params = fields.value
for (const key in params){
if (params[key] === null){
params[key] = 'none'
}
}
Edit(params['id'], params)
for (const item of Object.keys(fields.value)){
tableData.value[fields.value['fieldindex'] -1 ][item] = fields.value[item]
}
}else if (operation === '删除'){
Delete(data['id'])
tableData.value.splice(data['fieldindex'] -1 , 1)
}else if (operation === '增加'){
Add(fields.value)
let params = {}
for (const item of Object.keys(fields.value)){
params[item] = fields.value[item]
}
tableData.value.push(params)
}
})
.catch(() => {
ElMessage({
type: 'info',
message: '已取消',
})
})
}
const cancel = () => {
dialogVisible.value = false
more.value = false
ruleFormRef.value.clearValidate()
// ruleFormRef.value.resetFields()
}
async function open(str, data){
if (str === 'delete'){
confirm(str, data)
return
}
if (!ruleFormRef.value) return;
await ruleFormRef.value.validate((valid) => {
if (valid){
confirm(str, data)
// ruleFormRef.value.resetFields()
}else {
// ruleFormRef.value.resetFields()
return false
}
})
}
</script>
<style>
.el-row:not(:last-child) {
margin-bottom: 10px; /* 添加间距 */
}
</style>
\ No newline at end of file
import axios from "axios"
export async function DeviceProtocol(){
return axios.get('http://192.168.0.214:8000/op/dev_cmd_name_poll').then(
function (response){
return response.data
}
)
}
export async function ProtocolCmd(){
return axios.get('http://192.168.0.214:8000/op/all_dev_cmd_define').then(
function (response){
return response.data
}
)
}
export async function EditProtocolCmd(id,params){
const response = await axios.put('http://192.168.0.214:8000/op/all_dev_cmd_define/' + id + '/', params)
return response.data
}
export async function DeleteProtocolCmd(id){
return axios.delete('http://192.168.0.214:8000/op/all_dev_cmd_define/' + id).then(
function (response){
return response.data
}
)
}
export async function AddProtocolCMd(params){
return axios.post('http://192.168.0.214:8000/op/all_dev_cmd_define/' , params).then(
function (response){
return response.data
}
)
}
\ No newline at end of file
import {request} from '/lib/request'
/// 添加用户
// * username : string :
// * pwd : string :
// * role : integer :
// name : string :
// phone : string :
// sms : string :
// gender : integer :
// image : string :
// address : string :
// extendJson : string :
export async function UserAdminAdd(params){
const {data} = await request('/rest/user/admin/add', params)
return data.data
}
/// 删除冻结用户
// * id : integer :
// * off : integer : 0-删除,1-冻结,2-解冻
export async function UserAdminDel(params){
const {data} = await request('/rest/user/admin/del', params)
return data.data
}
/// 用户信息
// * uid : integer :
export async function UserAdminInfo(params){
const {data} = await request('/rest/user/admin/info', params)
return data.data
}
/// 用户列表
// departmentId : integer :
export async function UserAdminList(params){
const {data} = await request('/rest/user/admin/list', params)
return data.data
}
/// 用户列表 by role
// * roleId : integer :
export async function UserAdminListByRole(params){
const {data} = await request('/rest/user/admin/listByRole', params)
return data.data
}
/// 修改用户
// * id : integer :
// username : string :
// name : string :
// phone : string :
// gender : integer :
// image : string :
// address : string :
// pwd : string :
// role : integer :
// extendJson : string :
export async function UserAdminUpdate(params){
const {data} = await request('/rest/user/admin/update', params)
return data.data
}
/// 短信验证码获取
// * phone : string : 手机号
export async function UserGetVerifyCode(params){
const {data} = await request('/rest/user/getVerifyCode', params)
return data.data
}
/// 用户信息
export async function UserInfo(){
const {data} = await request('/rest/user/info')
return data.data
}
/// 登录
// username : string : 用户名
// phone : string : 手机号
// * pwd : string :
// schema : string :
export async function UserLogin(params){
const {data} = await request('/rest/user/login', params)
return data.data
}
/// 登录-用户名
// * username : string : 用户名
// * pwd : string :
// schema : string :
export async function UserLoginByUsername(params){
const {data} = await request('/rest/user/loginByUsername', params)
return data.data
}
/// 登出
export async function UserLogout(){
const {data} = await request('/rest/user/logout')
return data.data
}
/// 密码修改
// * oldPwd : string :
// * newPwd : string :
export async function UserUpdatePwd(params){
const {data} = await request('/rest/user/updatePwd', params)
return data.data
}
/// 更新用户信息
// username : string :
// name : string :
// phone : string :
// sms : string :
// gender : integer :
// image : string :
// address : string :
// oldPwd : string :
// newPwd : string :
// extendJson : string :
export async function UserUpdateUserInfo(params){
const {data} = await request('/rest/user/updateUserInfo', params)
return data.data
}
import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios'
import { ElMessage } from "element-plus";
// 创建axios的实例
const service = axios.create({
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL
// baseURL: process.env.NODE_ENV === 'production' ? `/` : '/api',
baseURL: '',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
},
withCredentials: false, // 跨域请求时是否需要使用凭证
timeout: 30000,
// `validateStatus` 定义对于给定的 HTTP 响应状态码是 resolve 或 reject promise 。
validateStatus() {
// `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
// 使用 async-await,处理 reject 情况较为繁琐,所以全部返回 resolve,在业务代码中处理异常
return true;
},
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [(data) => {
if (typeof data === 'string' && data.startsWith('{')) {
data = JSON.parse(data);
}
return data;
}]
});
// 添加请求拦截器
service.interceptors.request.use((config: InternalAxiosRequestConfig) => {
// console.log('发送请求之前', config.url);
// 获取 token ,并将其添加至请求头中
let token
// let token = store.state.user.token;
if(token){
config.headers.Authorization = token;
// config.headers.Authorization = 'Bearer ' + token;
}
return config;
}, (error: any) => {
// console.log('发送请求错误', error.response, error.data);
// 错误抛到业务代码
error.data = {
message: '服务器异常,请联系管理员!'
};
return Promise.reject(error);
});
//添加响应拦截器
service.interceptors.response.use((response: AxiosResponse) => {
// console.log('响应拦截', response.status, response);
/* 处理 http 错误,抛到业务代码 */
const status = response.status;
const decide = status < 200 || status >= 300;
if (decide) {
const message = showStatus(status);
// console.log("处理 http 错误", message);
if (typeof response.data === 'string') {
response.data = { message };
} else {
response.data.message = message;
}
ElMessage({
message,
type: 'error',
showClose: true
})
return Promise.reject(response.data);
}
return response;
}, (error: any) => {
// console.log('请求错误', error, axios.isCancel(error), error.message);
if (axios.isCancel(error)) {
// console.log('重复请求: ' + error.message);
ElMessage({
message: '请勿重复请求',
type: 'warning',
showClose: true
});
} else {
const message = '请求超时或服务器异常,请检查网络或联系管理员!';
ElMessage({
message,
type: 'error',
showClose: true
});
}
return Promise.reject(error);
});
const showStatus = (status: number) => {
let message = '';
switch (status) {
case 400:
message = '请求错误(400)';
break;
case 401:
message = '未授权,请重新登录(401)';
break;
case 403:
message = '拒绝访问(403)';
break;
case 404:
message = '请求出错(404)';
break;
case 408:
message = '请求超时(408)';
break;
case 500:
message = '服务器错误(500)';
break;
case 501:
message = '服务未实现(501)';
break;
case 502:
message = '网络错误(502)';
break;
case 503:
message = '服务不可用(503)';
break;
case 504:
message = '网络超时(504)';
break;
case 505:
message = 'HTTP版本不受支持(505)';
break;
default:
message = `连接出错(${status})!`;
}
return message;
// return `${message},请检查网络或联系管理员!`
};
export default service;
\ No newline at end of file
import service from '@/plugins/axios/axiosConfigs'
import { Get, Post, Delete, Put } from './types'; // 接口泛型
// 封装 get 方法,类型为Get
const get: Get = async (url, config) => {
const response = await service.get(url, { ...config});
return response.data;
};
const post: Post = async (url, params, config) => {
const response = await service.post(url, params, {...config});
return response.data;
};
// 封装 delete 方法
const del: Delete = async (url, config) => {
const response = await service.delete(url, {...config});
return response.data;
}
// 封装 put 方法
const put: Put = async (url, params, config) => {
const response = await service.put(url, params, {...config});
return response.data;
}
// 使用 request 统一调用
const request = {
get,
post,
del,
put
};
export default request;
\ No newline at end of file
import { InternalAxiosRequestConfig } from 'axios';
// 网络请求响应格式,T 是具体的接口返回类型数据
interface CustomSuccessData<T> {
code: number;
msg?: string;
message?: string;
data?: T;
[keys: string]: any;
}
interface Get {
<T>(url: string, config?: InternalAxiosRequestConfig): Promise<CustomSuccessData<T>>;
}
interface Post {
<T>(url: string, params?: string | object, config?: InternalAxiosRequestConfig): Promise<CustomSuccessData<T>>;
}
interface Delete {
<T>(url: string, config?: InternalAxiosRequestConfig): Promise<CustomSuccessData<T>>;
}
interface Put {
<T>(url: string, params?: string | object, config?: InternalAxiosRequestConfig): Promise<CustomSuccessData<T>>;
}
// ... delete 等等
export type {
CustomSuccessData,
Get,
Post,
Delete,
Put
}
\ No newline at end of file
...@@ -3,8 +3,59 @@ import { createRouter, createWebHistory } from 'vue-router'; ...@@ -3,8 +3,59 @@ import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHistory(),
routes: [ routes: [
// 定义路由... {
path: '/',
name: 'index',
component: () => import('@/views/index/home-page.vue'),
},
{
path: '/protocol',
name: 'protocol',
component: () => import("@/views/protocol/protocol.vue"),
},
{
path: '/communication',
name: 'communication',
component: () => import("@/views/DeviceCommunication.vue"),
}
] ]
}); })
// const router = createRouter({
// history: createWebHistory(),
// routes: [
// // 定义路由...
// {
// path: '/',
// name: 'index',
// component: () => import('@/views/Chat.vue'),
// props: { menuWith: '40%' },
// meta: {
// menu: true,
// authDisable: true
// },
// children: [
// {
// path: "/index",
// name: "receive-stats",
// component: () => import("../views/index/home-page.vue"),
// meta: {
// menuTitle: "首页",
// menuIcon: "fee",
// },
// },
// {
// path: "/protocol",
// name: "protocol",
// component: () => import("@/views/protocol/protocol.vue"),
// meta: {
// menuTitle: "协议",
// menuIcon: "fee",
// },
// },
// ]
// }
// ],
// });
export default router; export default router;
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
color-scheme: light dark; color-scheme: light dark;
color: rgba(255, 255, 255, 0.87); color: rgba(255, 255, 255, 0.87);
background-color: #242424; background-color: #ffffff;
font-synthesis: none; font-synthesis: none;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
...@@ -24,59 +24,12 @@ a:hover { ...@@ -24,59 +24,12 @@ a:hover {
color: #535bf2; color: #535bf2;
} }
body { * {
margin: 0; margin: 0;
display: flex; padding: 0;
/* place-items: center; */
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
} }
#app { #app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center; text-align: center;
width: 75%;
} }
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
<template>
<div class="common-layout">
<el-container>
<el-aside width="200px">
<kit-menu @handleMenuItemSelect="MenuItem"></kit-menu>
</el-aside>
<el-main>
<el-button @click="addDevice = true">新增模拟设备</el-button>
<component :is="currentComponent"></component>
</el-main>
</el-container>
</div>
<el-dialog v-model="addDevice" title="新增指令">
<el-form >
<el-form-item label="设备名称" :label-width="formLabelWidth">
<el-input autocomplete="off" />
</el-form-item>
<el-form-item label="设备英文名称" :label-width="formLabelWidth">
<el-input autocomplete="off" />
</el-form-item>
<el-form-item label="协议" :label-width="formLabelWidth">
<el-select>
<el-option label="TX"></el-option>
<el-option label="RX"></el-option>
</el-select>
</el-form-item>
<el-form-item label="通信方式" :label-width="formLabelWidth">
<el-select>
<el-option label="ASCII"></el-option>
<el-option label="HEX"></el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="addDevice = false">取消</el-button>
<el-button type="primary" @click="open">
确定
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import {ref, shallowRef} from "vue";
import {ElMessage, ElMessageBox} from "element-plus";
import KitMenu from "../../components/kit-menu.vue";
import KitDevice from "../../components/kit-device.vue";
const currentComponent = shallowRef(KitDevice)
const addDevice = ref(false)
const formLabelWidth = '140px'
function MenuItem(index){
console.log(index)
currentComponent.value = KitDevice
}
function open(){
ElMessageBox.confirm(
'是否确认增加?',
'Warning',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}
)
.then(() => {
ElMessage({
type: 'success',
message: '增加成功',
})
addDevice.value = false
})
.catch(() => {
ElMessage({
type: 'info',
message: '已取消',
})
})
}
</script>
<style>
body,html{
height: 100%;
}
html,body,.common-layout,.el-container{
margin: 0px;
padding: 0px;
height: 100%;
}
.el-aside {
background-color: #ffffff;
color: #333;
text-align: center;
line-height: 200px;
}
.el-main {
border: 1px solid;
/*background-color: #f3f4f6;*/
color: #333;
/*text-align: center;*/
}
</style>
<template>
<div class="flex items-center w-1/2">
<div style="width: 10%" >订阅主题</div>
<el-input style="width: 30%" class="ml-4"></el-input>
<el-button style="width: 15%" class="ml-4">连接mqtt</el-button>
</div>
<div class="flex mt-4" style="height: 80%;">
<div style="width: 40%; height: 100%">
<div style="height: 90%; border: 1px solid">
</div>
<div class="flex mt-4">
<el-input></el-input>
<el-button class="ml-4" @click="setting">设置指令</el-button>
<el-button>发送指令</el-button>
</div>
</div>
<div style="width: 58%; height: 100%; border: 1px solid;overflow: auto;" class="ml-4" >
<div style="border-bottom: 1px solid">
<el-button-group>
<el-button
class="square-button"
:type="type1 ? 'primary' : 'Default'"
@click="showComponent('real')"
>设备</el-button>
<el-button
class="square-button"
:type="type2 ? 'primary' : 'Default'"
@click="showComponent('virtual')"
>模拟设备</el-button>
</el-button-group>
</div>
<KitDevice v-if="tag" :tag = "tag"></KitDevice>
</div>
</div>
<div class="flex mt-4 items-center" style="height: 10%">
<div style="width: 90%; height: 100%;border: 1px solid;overflow: auto;" ref="messageContainer">
<span v-for="message in messages">
{{ message }}
<br />
</span>
</div>
<el-button class="ml-4" size="large">导出</el-button>
</div>
<el-dialog v-model="cmdVisible">
<el-form>
<el-form-item label="设备" :label-width="formLabelWidth">
<el-select v-model="cmds.device" @change="checkToShowInput">
<el-option label="option 1" value="option 1" />
</el-select>
</el-form-item>
<el-form-item label="指令名" :label-width="formLabelWidth">
<el-select v-model="cmds.cmd_name" @change="checkToShowInput">
<el-option label="option 1" value="option 1" />
</el-select>
</el-form-item>
<el-form-item label="某个字段" :label-width="formLabelWidth" v-if="show">
<el-input autocomplete="off" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="cmdVisible = false">取消</el-button>
<el-button type="primary" @click="cmdVisible = false">
确定
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import {onMounted, onUpdated, ref } from 'vue'
import KitDevice from "@/components/kit-device";
const messages = ref([1,2,3,4,5,6,7,8])
const messageContainer = ref(null);
const tag = ref('real')
const socket = ref(null)
const type1 = ref(true)
const type2 = ref(false)
const cmdVisible = ref(false)
const formLabelWidth = '140px'
const cmds = ref(
{device: '', cmd_name: ''}
)
const show = ref(false)
function scrollToBottom() {
if (messageContainer.value) {
messageContainer.value!.scrollTop = messageContainer.value!.scrollHeight;
}
}
onUpdated(() => {
// 在 messages 更新后滚动到底部
scrollToBottom();
});
onMounted(() => {
socket.value = new WebSocket('ws://'
+ 'localhost:8000'
+ '/ws/chat/mqtt/')
socket.value.onmessage = (e) => {
messages.value.push(e.data)
}
scrollToBottom();
})
const showComponent = (str) => {
if (str === 'real'){
type1.value = true
type2.value = false
}else if (str === 'virtual'){
type1.value = false
type2.value = true
}
tag.value = str
}
const checkToShowInput = () => {
show.value = cmds.value.device && cmds.value.cmd_name
}
const setting = () => {
cmdVisible.value = true
// cmds.value.device = ''
// cmds.value.cmd_name = ''
for (const key in cmds.value){
cmds.value[key] = ''
}
show.value = false
}
</script>
<style>
.square-button {
border-radius: 0;
}
</style>
\ No newline at end of file
<template>
<div class="w-screen h-screen">
<div class="w-full shadow-md flex justify-between items-center" :style="{height: headerHeight,backgroundColor:'#23479C', color:'white'}">
<div class="flex justify-center items-center cursor-pointer w-1/4" @click="routeTo('index')">
<div class="text-center">{{configKit.title}}</div>
</div>
<el-menu
:class="menuWith===''?'grow':''"
:style="menuWith===''?{}:{width: menuWith}"
activeTextColor="#00d0FF"
textColor="white"
:unique-opened="true"
:collapse-transition="false"
backgroundColor="#23479C"
mode="horizontal"
:default-active="storeCurrentRoute.name"
@select="routeTo">
<template v-for="(item, _) of storePageMenu" :key="item.name">
<el-sub-menu
v-if="menuItemFilter(item.children).length>0"
:index="item.name">
<template #title>
<div class="flex items-center">
<kit-icon class="w-4 h-4" :name="item.menuIcon"></kit-icon>
<span class="ml-2">{{item.menuTitle }}</span>
</div>
</template>
<el-menu-item
v-for="child of menuItemFilter(item.children)"
:index="child.name">
<template #title>
{{child.menuTitle}}
</template>
</el-menu-item>
</el-sub-menu>
<el-menu-item
v-else-if="item.name && item.component && (!item.authFunc || item.authFunc())"
:index="item.name">
<div class="flex justify-center items-center h-full">
<kit-icon class="w-4 h-4" :name="item.menuIcon"></kit-icon>
</div>
<template #title>
<span class="ml-2">{{ item.menuTitle }}</span>
</template>
</el-menu-item>
</template>
</el-menu>
<div class="rounded-full border border-white border-solid mx-4">
<kit-icon name="common-avatar" class="w-7 h-7 text-white" @click="usercenter=true"></kit-icon>
</div>
<el-drawer
v-model="usercenter"
title="个人中心"
size="240px"
direction="rtl">
<user-center class="text-black" />
</el-drawer>
</div>
<div v-if="storeCurrentRoute.name==='train-index'" class="overflow-auto p-4 w-full" style="background-color:#0b1634" :style="{height: 'calc(100vh - '+headerHeight+')'}">
<router-view />
</div>
<div v-else class="overflow-auto p-4 w-full bg-gray-100" :style="{height: 'calc(100vh - '+headerHeight+')'}">
<router-view />
</div>
</div>
</template>
<script setup lang="ts">
import { ref,onMounted} from 'vue';
import {storePageMenu} from "../../lib/router/index";
import {useRouter} from "vue-router";
import {configKit, storeCurrentRoute} from "../../lib/store/index.js";
import UserCenter from "/components/user-center";
//
// import {isBureau,isBureau0, isSchool} from "../store/model";
// import {storeTrainSelect} from "../store/train-select";
defineProps({
menuWith:{
type: String,
default: ""
}
})
const router = useRouter()
console.log(router)
// 顶部高
const headerHeight = ref('60px')
const usercenter = ref(false)
function routeTo(name){
router.push({name})
}
// menu
function menuItemFilter(itemChildren) {
if(!itemChildren) itemChildren = []
return itemChildren.filter((child) => !child.authFunc || child.authFunc());
}
onMounted(()=>{
})
</script>
<style>
.el-menu--horizontal{
border-bottom-width: 0;
}
</style>
<template>
<div class="button-container">
<el-button class="left-button" @click="addProtocol = true">新增协议</el-button>
<div class="right-buttons">
<el-button>导出数据库</el-button>
</div>
</div>
<kit-collapse class="mt-4"></kit-collapse>
<el-dialog title="新增协议" v-model="addProtocol">
<el-form >
<el-form-item label="协议名称" :label-width="formLabelWidth">
<el-input autocomplete="off" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="addProtocol = false">取消</el-button>
<el-button type="primary" @click="addProtocol = false">
确定
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import {ref} from 'vue';
import KitCollapse from "../../components/kit-collapse.vue";
const addProtocol = ref(false)
const formLabelWidth = '140px'
</script>
<style scoped>
.button-container {
display: flex;
justify-content: space-between; /* 使内部元素平均分布 */
align-items: center; /* 垂直居中 */
}
.left-button {
margin-right: auto; /* 将按钮1靠左 */
}
.right-buttons {
display: flex;
align-items: center; /* 垂直居中 */
}
</style>
<script setup lang="ts">
import { ElButton } from 'element-plus';
import axiox from 'axios';
const downloadFile = () => {
let url = '/api/downloadFile/'
axiox({
url,
method: 'GET',
responseType: 'blob'
}).then(res => {
// 下载文件
console.log(res)
const blob = new Blob([res.data], { type: 'application/x-sqlite3' });
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'xdc.sqlite';
link.click();
})
console.log('downloadFile');
}
</script>
<template>
<ElButton type="primary" @click="downloadFile">导出文件</ElButton>
</template>
\ No newline at end of file
<template>
<div class="h-screen w-screen flex justify-center items-center">
<div class="h-screen w-screen bg-cover" style=" background-image: url('src/assets/img/bg.png')">
<div class="text-white text-2xl text-center pt-20 pb-20">{{ configKit.title }}</div>
<div class="flex flex-col justify-center items-center gap-8">
<div class="text-2xl text-cyan-900 font-bold">登录</div>
<el-form
ref="form"
:model="modal"
label-position="left"
label-width="80px" size="large">
<el-form-item :rules="{required: true, message: '请填写', trigger: 'blur'}" label="用户名:" prop="username"
size="large">
<el-input v-model="modal.username" autocomplete="off" autofocus placeholder="用户名"
style="width: 220px" @keyup.enter.native="login()"/>
</el-form-item>
<el-form-item :rules="{required: true, message: '请填写', trigger: 'blur'}" label="密 码:" prop="pwd"
size="large">
<el-input v-model="modal.pwd" autocomplete="off" placeholder="密 码" style="width: 220px"
type="password" @keyup.enter.native="login()"/>
</el-form-item>
<el-form-item label="" prop="login" size="large">
<div class="flex flex-col items-center w-full">
<div class="flex justify-center w-full">
<el-button :loading="loading" class="w-full" size="large" type="primary" @click="login()">登录
</el-button>
</div>
<kit-err-channel id="login" style="width: 100%"/>
</div>
</el-form-item>
</el-form>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {onMounted, ref} from 'vue';
import {useRouter} from "vue-router";
import {configKit, storeUserInfo, submitErrChanel, updateStoreUserInfo} from "../../lib/store";
import {RouteName} from "../../lib/router";
import {useLoading} from "../../lib/service";
import {UserLogin} from "../dao/user";
const router = useRouter()
const loading = ref(false)
const modal = ref({role: 2})
const form = ref()
async function login() {
const valid = await form.value.validate();
if(!valid) return
await useLoading(loading, async function(){
submitErrChanel('login');
let data = await UserLogin(modal.value)
updateStoreUserInfo(data);
const redirect = {
name: RouteName.index,
};
await router.push(redirect);
})()
}
onMounted(function () {
})
</script>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
"baseUrl": "./", "baseUrl": "./",
//路径映射,相对于baseUrl //路径映射,相对于baseUrl
"paths": { "paths": {
"@/*": ["./src/*.vue", "./src/*.ts"] "@/*": ["./src/*.vue", "./src/*.ts", "./src/*.js"]
}, },
}, },
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment