提交 03ed339f authored 作者: 刘佳星-公司's avatar 刘佳星-公司

初始化

上级 ecbc88c6
# # 页面标题
VITE_APP_TITLE = '卫星仿真系统平台'
# # 开发环境配置
# VITE_APP_ENV = 'development'
# # 若依管理系统/开发环境
# VITE_API_URL = '/dev-api'
# NODE_ENV="development"
# VITE_API_URL = http://211.149.190.82:18080
# ENV = development # 本地环境
# VITE_API_URL = http://localhost:8888/ # 本地环境接口地址
# 本地环境
MODE_ENV = development
# 本地环境接口地址
VITE_API_URL = /api
\ No newline at end of file
# # 页面标题
VITE_APP_TITLE = '卫星仿真系统平台'
# # 生产环境配置
# VITE_APP_ENV = 'production'
# # 若依管理系统/生产环境
# VITE_API_URL = '/prod-api'
# # 是否在打包时开启压缩,支持 gzip 和 brotli
# VITE_BUILD_COMPRESS = gzip
# 线上环境
MODE_ENV = production
# 线上环境接口地址prod-webweibao.lingbtech.com
# VITE_API_URL = http://172.16.13.11:32089
# VITE_API_URL = http://172.16.13.11:32088
# VITE_API_URL = /prod-api
VITE_API_URL = /test-api
# 测试环境接口地址
MODE_ENV = test
# VITE_API_URL = 'http://172.16.13.11:32089'
VITE_API_URL = '/api'
\ No newline at end of file
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
{
"recommendations": ["Vue.volar"]
}
灭火器文件
\ No newline at end of file <!-- "license": "ISC",--许可证信息,暂时没加 -->
<!-- "type": "module",----使用 ES Modules(ECMAScript 模块) -->
<!-- 生产环境插件 -->
<!-- "@vueup/vue-quill": "1.2.0",--富文本编辑器.适配vue3--暂时不填 -->
<!-- dependencies--生产环境插件,devDependencies--开发环境插件 -->
<!-- "@vueuse/core": "10.11.0",----基于 Vue.js 的实用工具库 -->
<!-- "file-saver": "2.0.5",---把文件流保存成各种文件-下载 -->
<!-- "jsencrypt": "3.3.2" ---用于加密 -->
<!-- "nprogress": "0.2.0",--用于页面跳转时头部显示进度条样式 -->
<!-- "cesium": "^1.123.1",---cesium地图功能 -->
<!-- "pinia": "2.1.7",-----vue3的状态管理库 -->
<!--
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
users: [] // 初始状态是一个空数组
}),
getters: {
// 一个 getter 函数,返回数组中的用户数量
count: (state) => state.users.length
},
actions: {
// 一个 action 函数,用于添加用户
addUser(user) {
this.users.push(user)
}
} -->
<!-- "qs": "^6.13.1",---把对象转换成字符串 -->
<!-- "vue-cropper": "1.1.1",---用于用户上传头像的剪切--暂时不填 -->
<!-- vuedraggable---拖拽功能 -->
<!-- 开发环境插件 -->
<!-- "unplugin-auto-import": "0.17.6",----自动导入模块,减少手动导入操作,提高开发效率。 -->
<!-- "unplugin-vue-setup-extend-plus": "1.0.1",-在<script setup>语法中直接定义组件的name属性 -->
<!-- "vite-plugin-compression": "0.5.1",---压缩文件,提高加载速度和用户体验 -->
\ No newline at end of file
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const createPinia: typeof import('pinia')['createPinia']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defineStore: typeof import('pinia')['defineStore']
const effectScope: typeof import('vue')['effectScope']
const getActivePinia: typeof import('pinia')['getActivePinia']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const mapActions: typeof import('pinia')['mapActions']
const mapGetters: typeof import('pinia')['mapGetters']
const mapState: typeof import('pinia')['mapState']
const mapStores: typeof import('pinia')['mapStores']
const mapWritableState: typeof import('pinia')['mapWritableState']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const setActivePinia: typeof import('pinia')['setActivePinia']
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const storeToRefs: typeof import('pinia')['storeToRefs']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId']
const useLink: typeof import('vue-router')['useLink']
const useModel: typeof import('vue')['useModel']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>自定义项目</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "myapp",
"description": "创建自定义项目解释",
"author": "作者信息",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --open",
"test": "vite build --mode test",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"ant-design-vue": "^4.2.6",
"axios": "0.28.1",
"echarts": "5.5.1",
"element-plus": "^2.9.6",
"file-saver": "2.0.5",
"js-cookie": "3.0.5",
"jsencrypt": "3.3.2",
"nprogress": "0.2.0",
"pinia": "2.1.7",
"qs": "^6.13.1",
"vue": "^3.5.13",
"vue-router": "^4.5.0",
"vuedraggable": "4.1.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"sass": "1.77.5",
"unplugin-auto-import": "0.17.6",
"unplugin-vue-setup-extend-plus": "1.0.1",
"vite": "^6.2.0",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-svg-icons": "2.0.1"
}
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
\ No newline at end of file
<template>
<div>
<router-view />
</div>
</template>
<script setup>
onMounted(() => {
nextTick(() => {
// 初始化主题样式
})
})
</script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
</style>
import qs from 'qs'
import request from '@/utils/request'
// 新增天线组
export function addcommonAntennaGroup(data) {
return request({
url: '/simu/commonAntenna',
method: 'post',
data,
})
}
// 修改
export function upcommonAntennaGroup(data) {
return request({
url: '/simu/commonAntenna',
method: 'put',
data,
})
}
// 详情
export function getantenna(data) {
return request({
url: `/simu/commonAntenna/${data.id}`,
method: 'get',
})
}
// 列表
export function getlist(data) {
return request({
url: `/simu/commonAntenna/list?${qs.stringify(data)}`,
method: 'get',
})
}
// 删除
export function deleantenna(data) {
return request({
url: `/simu/commonAntenna/${data.id}`,
method: 'delete',
})
}
\ No newline at end of file
import axios from 'axios'
import request from '../../utils/request'
import qs from 'qs'
export default {
// 保留请求取消
cancels: {},
// 话务模型----------------------------------------------------------------------------------------------------------------
// 话务列表
simu_voiceslist(params) {
this.cancels['simu_voiceslist']?.()
return request.get(
`/simu/voice/list?${qs.stringify(params)}`,
params,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_voiceslist'] = c
})
}
)
},
//新增话务
simu_voicesAdd(params) {
this.cancels['simu_voicesAdd']?.()
return request.post(
`/simu/voice`,
params,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_voicesAdd'] = c
})
}
)
},
//修改话务
simu_voicesput(params) {
this.cancels['simu_voicesput']?.()
return request.put(
`/simu/voice`,
params,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_voicesput'] = c
})
}
)
},
//删除话务
simu_voicesRemo(data) {
this.cancels['simu_voicesRemo']?.()
return request.delete(
`/simu/voice/${data.ids}`,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_voicesRemo'] = c
})
}
)
},
//话务详细信息
simu_voicesId(params) {
this.cancels['simu_voicesId']?.()
return request.get(
`/simu/voice/${params.id}`,
params,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_voicesId'] = c
})
}
)
},
// 话务模型结束----------------------------------------------------------------------------------------------------------------
// 业务模型----------------------------------------------------------------------------------------------------------------
// 业务列表
simu_businesslist(params) {
this.cancels['simu_businesslist']?.()
return request.get(
`/simu/business/list?${qs.stringify(params)}`,
params,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_businesslist'] = c
})
}
)
},
//新增业务
simu_businessAdd(params) {
this.cancels['simu_businessAdd']?.()
return request.post(
`/simu/business`,
params,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_businessAdd'] = c
})
}
)
},
//修改业务
simu_businessput(params) {
this.cancels['simu_businessput']?.()
return request.put(
`/simu/business`,
params,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_businessput'] = c
})
}
)
},
//删除业务
simu_businessRemo(data) {
this.cancels['simu_businessRemo']?.()
return request.delete(
`/simu/business/${data.ids}`,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_businessRemo'] = c
})
}
)
},
//业务详细信息
simu_businessId(params) {
this.cancels['simu_businessId']?.()
return request.get(
`/simu/business/${params.id}`,
params,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_businessId'] = c
})
}
)
},
// 业务模型结束------------------------------------------------------------------------------------------------------------- ----
//接口调节-------------------------------------------------------------------------------------------------------------
simu_rdFileInsList(params) {
this.cancels['simu_rdFileInsList']?.()
return request.get(
`/simu/rdFileIns/list?${qs.stringify(params)}`,
params,
{
cancelToken: new axios.CancelToken(c => {
this.cancels['simu_rdFileInsList'] = c
})
}
)
},
}
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
\ No newline at end of file
<template>
<div class="upload-file">
<el-upload multiple :action="uploadFileUrl" :before-upload="handleBeforeUpload" :file-list="fileList" :limit="limit"
:on-error="handleUploadError" :on-exceed="handleExceed" :on-success="handleUploadSuccess" :show-file-list="false"
:headers="headers" class="upload-file-uploader" ref="fileUpload">
<!-- 上传按钮 -->
<el-button type="primary">选取文件</el-button>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" v-if="showTip">
请上传
<template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
<template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
的文件
</div>
<!-- 文件列表 -->
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
<li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
<el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link>
<div class="ele-upload-list__item-content-action">
<el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
</div>
</li>
</transition-group>
</div>
</template>
<script setup>
// import { getToken } from "@/utils/auth";
const props = defineProps({
modelValue: [String, Object, Array],
// 数量限制
limit: {
type: Number,
default: 5,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["doc", "xls", "ppt", "txt", "pdf"],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
}
});
const { proxy } = getCurrentInstance();
const emit = defineEmits();
const number = ref(0);
const uploadList = ref([]);
const baseUrl = import.meta.env.VITE_API_URL;
const uploadFileUrl = ref(import.meta.env.VITE_API_URL + "/common/upload"); // 上传文件服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() });
const fileList = ref([]);
const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize)
);
watch(() => props.modelValue, val => {
if (val) {
let temp = 1;
// 首先将值转为数组
const list = Array.isArray(val) ? val : props.modelValue.split(',');
// 然后将数组转为对象数组
fileList.value = list.map(item => {
if (typeof item === "string") {
item = { name: item, url: item };
}
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
} else {
fileList.value = [];
return [];
}
}, { deep: true, immediate: true });
// 上传前校检格式和大小
function handleBeforeUpload(file) {
// 校检文件类型
if (props.fileType.length) {
const fileName = file.name.split('.');
const fileExt = fileName[fileName.length - 1];
const isTypeOk = props.fileType.indexOf(fileExt) >= 0;
if (!isTypeOk) {
proxy.$modal.msgError(`文件格式不正确,请上传${props.fileType.join("/")}格式文件!`);
return false;
}
}
// 校检文件名是否包含特殊字符
if (file.name.includes(',')) {
proxy.$modal.msgError('文件名不正确,不能包含英文逗号!');
return false;
}
// 校检文件大小
if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) {
proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
return false;
}
}
proxy.$modal.loading("正在上传文件,请稍候...");
number.value++;
return true;
}
// 文件个数超出
function handleExceed() {
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
}
// 上传失败
function handleUploadError(err) {
proxy.$modal.msgError("上传文件失败");
}
// 上传成功回调
function handleUploadSuccess(res, file) {
if (res.code === 200) {
uploadList.value.push({ name: res.fileName, url: res.fileName });
uploadedSuccessfully();
} else {
number.value--;
proxy.$modal.closeLoading();
proxy.$modal.msgError(res.msg);
proxy.$refs.fileUpload.handleRemove(file);
uploadedSuccessfully();
}
}
// 删除文件
function handleDelete(index) {
fileList.value.splice(index, 1);
emit("update:modelValue", listToString(fileList.value));
}
// 上传结束处理
function uploadedSuccessfully() {
if (number.value > 0 && uploadList.value.length === number.value) {
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
uploadList.value = [];
number.value = 0;
emit("update:modelValue", listToString(fileList.value));
proxy.$modal.closeLoading();
}
}
// 获取文件名称
function getFileName(name) {
// 如果是url那么取最后的名字 如果不是直接返回
if (name.lastIndexOf("/") > -1) {
return name.slice(name.lastIndexOf("/") + 1);
} else {
return name;
}
}
// 对象转成指定字符串分隔
function listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
if (list[i].url) {
strs += list[i].url + separator;
}
}
return strs != '' ? strs.substr(0, strs.length - 1) : '';
}
</script>
<style scoped lang="scss">
.upload-file-uploader {
margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
border: 1px solid #e4e7ed;
line-height: 2;
margin-bottom: 10px;
position: relative;
}
.upload-file-list .ele-upload-list__item-content {
display: flex;
justify-content: space-between;
align-items: center;
color: inherit;
}
.ele-upload-list__item-content-action .el-link {
margin-right: 10px;
}
</style>
<script setup>
import { ref } from 'vue'
defineProps({
msg: String,
})
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Learn more about IDE Support for Vue in the
<a
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
target="_blank"
>Vue Docs Scaling up Guide</a
>.
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>
<template>
<el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`"
:preview-src-list="realSrcList" preview-teleported>
<template #error>
<div class="image-slot">
<el-icon><picture-filled /></el-icon>
</div>
</template>
</el-image>
</template>
<script setup>
// import { isExternal } from "@/utils/validate";
const props = defineProps({
src: {
type: String,
default: ""
},
width: {
type: [Number, String],
default: ""
},
height: {
type: [Number, String],
default: ""
}
});
const realSrc = computed(() => {
if (!props.src) {
return;
}
let real_src = props.src.split(",")[0];
if (isExternal(real_src)) {
return real_src;
}
return import.meta.env.VITE_API_URL + real_src;
});
const realSrcList = computed(() => {
if (!props.src) {
return;
}
let real_src_list = props.src.split(",");
let srcList = [];
real_src_list.forEach(item => {
if (isExternal(item)) {
return srcList.push(item);
}
return srcList.push(import.meta.env.VITE_API_URL + item);
});
return srcList;
});
const realWidth = computed(() =>
typeof props.width == "string" ? props.width : `${props.width}px`
);
const realHeight = computed(() =>
typeof props.height == "string" ? props.height : `${props.height}px`
);
</script>
<style lang="scss" scoped>
.el-image {
border-radius: 5px;
background-color: #ebeef5;
box-shadow: 0 0 5px 1px #ccc;
:deep(.el-image__inner) {
transition: all 0.3s;
cursor: pointer;
&:hover {
transform: scale(1.2);
}
}
:deep(.image-slot) {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
color: #909399;
font-size: 30px;
}
}
</style>
<template>
<div class="component-upload-image">
<el-upload multiple :action="uploadImgUrl" list-type="picture-card" :on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload" :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed"
ref="imageUpload" :before-remove="handleDelete" :show-file-list="true" :headers="headers" :file-list="fileList"
:on-preview="handlePictureCardPreview" :class="{ hide: fileList.length >= limit }">
<el-icon class="avatar-uploader-icon">
<plus />
</el-icon>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" v-if="showTip">
请上传
<template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
</template>
的文件
</div>
<el-dialog v-model="dialogVisible" title="预览" width="800px" append-to-body>
<img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
</el-dialog>
</div>
</template>
<script setup>
import { getToken } from "@/utils/auth";
// import { isExternal } from "@/utils/validate";
const props = defineProps({
modelValue: [String, Object, Array],
// 图片数量限制
limit: {
type: Number,
default: 5,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["png", "jpg", "jpeg"],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
},
});
const { proxy } = getCurrentInstance();
const emit = defineEmits();
const number = ref(0);
const uploadList = ref([]);
const dialogImageUrl = ref("");
const dialogVisible = ref(false);
const baseUrl = import.meta.env.VITE_API_URL;
const uploadImgUrl = ref(import.meta.env.VITE_API_URL + "/common/upload"); // 上传的图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() });
const fileList = ref([]);
const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize)
);
watch(() => props.modelValue, val => {
if (val) {
// 首先将值转为数组
const list = Array.isArray(val) ? val : props.modelValue.split(",");
// 然后将数组转为对象数组
fileList.value = list.map(item => {
if (typeof item === "string") {
if (item.indexOf(baseUrl) === -1 && !isExternal(item)) {
item = { name: baseUrl + item, url: baseUrl + item };
} else {
item = { name: item, url: item };
}
}
return item;
});
} else {
fileList.value = [];
return [];
}
}, { deep: true, immediate: true });
// 上传前loading加载
function handleBeforeUpload(file) {
let isImg = false;
if (props.fileType.length) {
let fileExtension = "";
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
isImg = props.fileType.some(type => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
} else {
isImg = file.type.indexOf("image") > -1;
}
if (!isImg) {
proxy.$modal.msgError(`文件格式不正确,请上传${props.fileType.join("/")}图片格式文件!`);
return false;
}
if (file.name.includes(',')) {
proxy.$modal.msgError('文件名不正确,不能包含英文逗号!');
return false;
}
if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) {
proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
return false;
}
}
proxy.$modal.loading("正在上传图片,请稍候...");
number.value++;
}
// 文件个数超出
function handleExceed() {
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
}
// 上传成功回调
function handleUploadSuccess(res, file) {
if (res.code === 200) {
uploadList.value.push({ name: res.fileName, url: res.fileName });
uploadedSuccessfully();
} else {
number.value--;
proxy.$modal.closeLoading();
proxy.$modal.msgError(res.msg);
proxy.$refs.imageUpload.handleRemove(file);
uploadedSuccessfully();
}
}
// 删除图片
function handleDelete(file) {
const findex = fileList.value.map(f => f.name).indexOf(file.name);
if (findex > -1 && uploadList.value.length === number.value) {
fileList.value.splice(findex, 1);
emit("update:modelValue", listToString(fileList.value));
return false;
}
}
// 上传结束处理
function uploadedSuccessfully() {
if (number.value > 0 && uploadList.value.length === number.value) {
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
uploadList.value = [];
number.value = 0;
emit("update:modelValue", listToString(fileList.value));
proxy.$modal.closeLoading();
}
}
// 上传失败
function handleUploadError() {
proxy.$modal.msgError("上传图片失败");
proxy.$modal.closeLoading();
}
// 预览
function handlePictureCardPreview(file) {
dialogImageUrl.value = file.url;
dialogVisible.value = true;
}
// 对象转成指定字符串分隔
function listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
if (undefined !== list[i].url && list[i].url.indexOf("blob:") !== 0) {
strs += list[i].url.replace(baseUrl, "") + separator;
}
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
}
</script>
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
:deep(.hide .el-upload--picture-card) {
display: none;
}
</style>
\ No newline at end of file
<template>
<svg :class="svgClass" aria-hidden="true">
<use :xlink:href="iconName" :fill="color" />
</svg>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
},
color: {
type: String,
default: ''
},
},
setup(props) {
return {
iconName: computed(() => `#icon-${props.iconClass}`),
svgClass: computed(() => {
if (props.className) {
return `svg-icon ${props.className}`
}
return 'svg-icon'
})
}
}
})
</script>
<style scope lang="scss">
.sub-el-icon,
.nav-icon {
display: inline-block;
font-size: 15px;
margin-right: 12px;
position: relative;
}
.svg-icon {
width: 1em;
height: 1em;
position: relative;
fill: currentColor;
vertical-align: -2px;
}
</style>
import * as components from '@element-plus/icons-vue'
export default {
install: (app) => {
for (const key in components) {
const componentConfig = components[key];
app.component(componentConfig.name, componentConfig);
}
},
};
import hasRole from './permission/hasRole'
import hasPermi from './permission/hasPermi'
export default function directive(app) {
app.directive('hasRole', hasRole)
app.directive('hasPermi', hasPermi)
}
\ No newline at end of file
/**
* v-hasPermi 操作权限处理
* Copyright (c) 2019 ruoyi
*/
// import useUserStore from '@/store/modules/user'
export default {
mounted(el, binding, vnode) {
// const { value } = binding
// const all_permission = "*:*:*";
// const permissions = useUserStore().permissions
// if (value && value instanceof Array && value.length > 0) {
// const permissionFlag = value
// const hasPermissions = permissions.some(permission => {
// return all_permission === permission || permissionFlag.includes(permission)
// })
// if (!hasPermissions) {
// el.parentNode && el.parentNode.removeChild(el)
// }
// } else {
// throw new Error(`请设置操作权限标签值`)
// }
}
}
// import useUserStore from '@/store/modules/user'
export default {
mounted(el, binding, vnode) {
// const { value } = binding
// const super_admin = "admin";
// const roles = useUserStore().roles
// if (value && value instanceof Array && value.length > 0) {
// const roleFlag = value
// const hasRole = roles.some(role => {
// return super_admin === role || roleFlag.includes(role)
// })
// if (!hasRole) {
// el.parentNode && el.parentNode.removeChild(el)
// }
// } else {
// throw new Error(`请设置角色权限标签值`)
// }
}
}
<template>
<div>
<router-view v-slot="{ Component, route }" :key="$route.fullPath">
<keep-alive>
<component v-if="!route.meta.link" :is="Component" :key="route.path" />
</keep-alive>
</router-view>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
onMounted(() => {
console.log('加载');
})
</script>
\ No newline at end of file
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import './style.css'
import App from './App.vue'
//导入ant-design-vue框架
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/reset.css';
// 导入element-plus框架
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import locale from 'element-plus/es/locale/lang/zh-cn'
//Cookies插件
import Cookies from 'js-cookie'
//引入公共样式
import '@/static/scss/index.scss' // global css
import '@/static/css/index.css'
import '@/static/elementPlus/element-plus.scss'
import store from './store/index.js'
import router from './router/index.js'
import SvgIcon from '@/components/SvgIcon/index.vue' //
import elementIcons from '@/components/SvgIcon/svgicon.js'
import './permission' // 路由拦截和加载页面进度条
// 全局配置组件
// 文件上传组件
import FileUpload from "@/components/FileUpload/index.vue"
// 图片上传组件
import ImageUpload from "@/components/ImageUpload/index.vue"
// 图片预览组件
import ImagePreview from "@/components/ImagePreview/index.vue"
// import VueCropper from 'vue-cropper'//用户头像裁剪
import { useDict } from '@/utils/dict'
import directive from './directive' // 导入公共函数
const app = createApp(App)
const pinia = createPinia();
// 全局方法挂载
app.config.globalProperties.useDict = useDict
// 全局组件挂载
app.component('FileUpload', FileUpload)
app.component('ImageUpload', ImageUpload)
app.component('ImagePreview', ImagePreview)
app.use(router)
app.use(store)
app.use(elementIcons)
// app.use(VueCropper)
app.component('svg-icon', SvgIcon)
directive(app)//挂载全局函数
app.use(Antd)
app.use(pinia)
// 使用element-plus 并且设置全局的大小
app.use(ElementPlus, {
locale: locale,
// 支持 large、default、small
size: Cookies.get('size') || 'default'
})
app.mount('#app')
import router from './router'
import { ElMessage } from 'element-plus'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'
// import { isHttp } from '@/utils/validate'
// import { isRelogin } from '@/utils/request'
// import useUserStore from '@/store/modules/user'
// import useSettingsStore from '@/store/modules/settings'
// import usePermissionStore from '@/store/modules/permission'
// NProgress.configure({ showSpinner: false });
// const whiteList = ['/login', '/register'];//白名单
router.beforeEach((to, from, next) => {
console.log(to, from);
next()
// NProgress.start()
// if (getToken()) {
// to.meta.title && useSettingsStore().setTitle(to.meta.title)
// /* has token*/
// if (to.path === '/login') {
// next({ path: '/' })
// NProgress.done()
// } else if (whiteList.indexOf(to.path) !== -1) {
// next()
// } else {
// if (useUserStore().roles.length === 0) {
// isRelogin.show = true
// // 判断当前用户是否已拉取完user_info信息
// useUserStore().getInfo().then(() => {
// isRelogin.show = false
// usePermissionStore().generateRoutes().then(accessRoutes => {
// let routeSatus = false
// // 根据roles权限生成可访问的路由表
// accessRoutes.forEach(route => {
// if (!isHttp(route.path)) {
// router.addRoute(route) // 动态添加可访问路由表
// }
// route.children.forEach(it => {
// if (it.path == "simulationRoom") {
// routeSatus = true
// }
// })
// })
// if (routeSatus) {
// next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
// } else {
// next('/task')
// }
// })
// }).catch(err => {
// useUserStore().logOut().then(() => {
// ElMessage.error(err)
// next({ path: '/' })
// })
// })
// } else {
// next()
// }
// }
// } else {
// console.log('token过期或者不存在');
// // 没有token
// if (whiteList.indexOf(to.path) !== -1) {
// console.log('白名单');
// // 在免登录白名单,直接进入
// next()
// } else {
// console.log(to.fullPath, '重定向');
// next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
// NProgress.done()
// }
// }
})
router.afterEach(() => {
// NProgress.done()
})
import { createWebHistory, createRouter, createWebHashHistory } from 'vue-router'
/* Layout */
import Layout from '@/layout/index.vue'
console.log(Layout);
/**
* Note: 路由配置项
*
* hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
* alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
* // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
* // 若你想不管路由下面的 children 声明的个数都显示你的根路由
* // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
* redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
* name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
* query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
* roles: ['admin', 'common'] // 访问路由的角色权限
* permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限
* meta : {
noCache: true // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg
breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示
activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。
}
*/
// 公共路由
export const constantRoutes = [
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect/index.vue')
}
]
},
{
path: '/login',
component: () => import('@/views/login/index.vue'),
hidden: true
},
{
path: "/:pathMatch(.*)*",
component: () => import('@/views/error/404.vue'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error/401.vue'),
hidden: true
},
{
path: '',
component: Layout,
// redirect: '/home',
// hidden: true,//注释平台首页
children: [
{
path: '/home',
component: () => import('../views/home/index.vue'),
// component: () => import('../views/index'),
name: 'Home',
meta: { title: '首页', icon: 'dashboard', affix: true }
},
{
// 配置页面
path: '/disposition/peizhi',
component: () => import('../views/peizhi/index.vue'),
hidden: true
}
]
},
]
const router = createRouter({
history: createWebHistory(),
routes: constantRoutes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return { top: 0 }
}
},
});
export default router;
import { createPinia } from 'pinia'
const store = createPinia()
export default store
\ No newline at end of file
import Cookies from 'js-cookie'
const useAppStore = defineStore(
'app',
{
state: () => ({
sidebar: {
opened: true,
withoutAnimation: false,
hide: false
},
device: 'desktop',
size: Cookies.get('size') || 'default'
}),
actions: {
toggleSideBar(withoutAnimation) {
if (this.sidebar.hide) {
return false;
}
this.sidebar.opened = true
this.sidebar.withoutAnimation = withoutAnimation
if (this.sidebar.opened) {
Cookies.set('sidebarStatus', 1)
} else {
Cookies.set('sidebarStatus', 0)
}
},
closeSideBar({ withoutAnimation }) {
Cookies.set('sidebarStatus', 0)
this.sidebar.opened = true
this.sidebar.withoutAnimation = withoutAnimation
},
toggleDevice(device) {
this.device = device
},
setSize(size) {
this.size = size;
Cookies.set('size', size)
},
toggleSideBarHide(status) {
this.sidebar.hide = status
}
}
})
export default useAppStore
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
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 {
max-width: 1280px;
margin: 0 auto;
padding: 0;
/* text-align: center; */
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
// import useDictStore from '@/store/modules/dict'
// import { getDicts } from '@/api/system/dict/data'
/**
* 获取字典数据
*/
export function useDict(...args) {
const res = ref({});
return (() => {
// args.forEach((dictType, index) => {
// res.value[dictType] = [];
// const dicts = useDictStore().getDict(dictType);
// if (dicts) {
// res.value[dictType] = dicts;
// } else {
// getDicts(dictType).then(resp => {
// res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass }))
// useDictStore().setDict(dictType, res.value[dictType]);
// })
// }
// })
return toRefs(res.value);
})()
}
\ No newline at end of file
/**
* 通用js方法封装处理
* Copyright (c) 2019 ruoyi
*/
// 日期格式化
export function parseTime(time, pattern) {
if (arguments.length === 0 || !time) {
return null
}
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
time = parseInt(time)
} else if (typeof time === 'string') {
time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
/**
* 参数处理
* @param {*} params 参数
*/
export function tansParams(params) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName];
var part = encodeURIComponent(propName) + "=";
if (value !== null && value !== "" && typeof (value) !== "undefined") {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
let params = propName + '[' + key + ']';
var subPart = encodeURIComponent(params) + "=";
result += subPart + encodeURIComponent(value[key]) + "&";
}
}
} else {
result += part + encodeURIComponent(value) + "&";
}
}
}
return result
}
// 返回项目路径
export function getNormalPath(p) {
if (p.length === 0 || !p || p == 'undefined') {
return p
};
let res = p.replace('//', '/')
if (res[res.length - 1] === '/') {
return res.slice(0, res.length - 1)
}
return res;
}
const sessionCache = {
set(key, value) {
if (!sessionStorage) {
return
}
if (key != null && value != null) {
sessionStorage.setItem(key, value)
}
},
get(key) {
if (!sessionStorage) {
return null
}
if (key == null) {
return null
}
return sessionStorage.getItem(key)
},
setJSON(key, jsonValue) {
if (jsonValue != null) {
this.set(key, JSON.stringify(jsonValue))
}
},
getJSON(key) {
const value = this.get(key)
if (value != null) {
return JSON.parse(value)
}
},
remove(key) {
sessionStorage.removeItem(key);
}
}
const localCache = {
set(key, value) {
if (!localStorage) {
return
}
if (key != null && value != null) {
localStorage.setItem(key, value)
}
},
get(key) {
if (!localStorage) {
return null
}
if (key == null) {
return null
}
return localStorage.getItem(key)
},
setJSON(key, jsonValue) {
if (jsonValue != null) {
this.set(key, JSON.stringify(jsonValue))
}
},
getJSON(key) {
const value = this.get(key)
if (value != null) {
return JSON.parse(value)
}
},
remove(key) {
localStorage.removeItem(key);
}
}
export default {
/**
* 会话级缓存
*/
session: sessionCache,
/**
* 本地缓存
*/
local: localCache
}
import axios from 'axios'
import { ElNotification, ElMessageBox, ElMessage, ElLoading } from 'element-plus'
import { getToken } from '@/utils/auth.js'
import { tansParams } from '@/utils/function.js'
import local from '@/utils/local.js'
import { saveAs } from 'file-saver'
// import useUserStore from '@/store/modules/user'
let downloadLoadingInstance;
// 是否显示重新登录
export let isRelogin = { show: false };
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
baseURL: import.meta.env.VITE_API_URL,
// 超时
timeout: 60000
})
// request拦截器
service.interceptors.request.use(config => {
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params);
url = url.slice(0, -1);
config.params = {};
config.url = url;
}
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = {
url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime()
}
const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小
const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
if (requestSize >= limitSize) {
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
return config;
}
const sessionObj = local.session.getJSON('sessionObj')
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
local.session.setJSON('sessionObj', requestObj)
} else {
const s_url = sessionObj.url; // 请求地址
const s_data = sessionObj.data; // 请求数据
const s_time = sessionObj.time; // 请求时间
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
// console.log(s_data, requestObj.data, requestObj.time, s_time, s_url, requestObj.url);
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交';
console.warn(`[${s_url}]: ` + message)
return Promise.reject(new Error(message))
} else {
local.session.setJSON('sessionObj', requestObj)
}
}
}
return config
}, error => {
console.log(error)
Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(res => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200;
// 获取错误信息
const msg = res.data.msg || '未知错误';
// 二进制数据则直接返回
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res.data
}
if (code === 401) {
if (!isRelogin.show) {
isRelogin.show = true;
ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
isRelogin.show = false;
// useUserStore().logOut().then(() => {
location.href = '/';
// })
}).catch(() => {
isRelogin.show = false;
});
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
ElMessage({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code === 601) {
ElMessage({ message: msg, type: 'warning' })
return Promise.reject(new Error(msg))
} else if (code !== 200) {
ElNotification.error({ title: msg })
return Promise.reject('error')
} else {
return Promise.resolve(res.data)
}
},
error => {
console.log('err' + error)
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
ElMessage({ message: message, type: 'error', duration: 5 * 1000 })
return Promise.reject(error)
}
)
// 通用下载方法
export function download(url, params, filename, config) {
downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })
return service.post(url, params, {
transformRequest: [(params) => { return tansParams(params) }],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob',
...config
}).then(async (data) => {
if (data.type !== 'application/json') {
const blob = new Blob([data])
saveAs(blob, filename)
} else {
const resText = await data.text();
const rspObj = JSON.parse(resText);
const errMsg = rspObj.msg || '下载文件失败,请联系管理员!';
ElMessage.error(errMsg);
}
downloadLoadingInstance.close();
}).catch((r) => {
console.error(r)
ElMessage.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close();
})
}
export default service
<template>
<div class="errPage-container">
<el-button icon="arrow-left" class="pan-back-btn" @click="back">
返回
</el-button>
<el-row>
<el-col :span="12">
<h1 class="text-jumbo text-ginormous">
401错误!
</h1>
<h2>您没有访问权限!</h2>
<h6>对不起,您没有访问权限,请不要进行非法操作!您可以返回主页面</h6>
<ul class="list-unstyled">
<li class="link-type">
<router-link to="/">
回首页
</router-link>
</li>
</ul>
</el-col>
<el-col :span="12">
<img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream.">
</el-col>
</el-row>
</div>
</template>
<script setup>
import errImage from "@/static/image/401.gif";
let { proxy } = getCurrentInstance();
const errGif = ref(errImage + "?" + +new Date());
function back() {
if (proxy.$route.query.noGoBack) {
proxy.$router.push({ path: "/" });
} else {
proxy.$router.go(-1);
}
}
</script>
<style lang="scss" scoped>
.errPage-container {
width: 800px;
max-width: 100%;
margin: 100px auto;
.pan-back-btn {
background: #008489;
color: #fff;
border: none !important;
}
.pan-gif {
margin: 0 auto;
display: block;
}
.pan-img {
display: block;
margin: 0 auto;
width: 100%;
}
.text-jumbo {
font-size: 60px;
font-weight: 700;
color: #484848;
}
.list-unstyled {
font-size: 14px;
li {
padding-bottom: 5px;
}
a {
color: #008489;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
</style>
<template>
<div class="wscn-http404-container">
<div class="wscn-http404">
<div class="pic-404">
<img class="pic-404__parent" src="@/static/image/404.png" alt="404">
<img class="pic-404__child left" src="@/static/image/404_cloud.png" alt="404">
<img class="pic-404__child mid" src="@/static/image/404_cloud.png" alt="404">
<img class="pic-404__child right" src="@/static/image/404_cloud.png" alt="404">
</div>
<div class="bullshit">
<div class="bullshit__oops">
404错误!
</div>
<div class="bullshit__headline">
{{ message }}
</div>
<div class="bullshit__info">
对不起,您正在寻找的页面不存在。尝试检查URL的错误,然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容。
</div>
<router-link to="/index" class="bullshit__return-home">
返回首页
</router-link>
</div>
</div>
</div>
</template>
<script setup>
let message = computed(() => {
return '找不到网页!'
})
</script>
<style lang="scss" scoped>
.wscn-http404-container {
transform: translate(-50%, -50%);
position: absolute;
top: 40%;
left: 50%;
}
.wscn-http404 {
position: relative;
width: 1200px;
padding: 0 50px;
overflow: hidden;
.pic-404 {
position: relative;
float: left;
width: 600px;
overflow: hidden;
&__parent {
width: 100%;
}
&__child {
position: absolute;
&.left {
width: 80px;
top: 17px;
left: 220px;
opacity: 0;
animation-name: cloudLeft;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
&.mid {
width: 46px;
top: 10px;
left: 420px;
opacity: 0;
animation-name: cloudMid;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1.2s;
}
&.right {
width: 62px;
top: 100px;
left: 500px;
opacity: 0;
animation-name: cloudRight;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
@keyframes cloudLeft {
0% {
top: 17px;
left: 220px;
opacity: 0;
}
20% {
top: 33px;
left: 188px;
opacity: 1;
}
80% {
top: 81px;
left: 92px;
opacity: 1;
}
100% {
top: 97px;
left: 60px;
opacity: 0;
}
}
@keyframes cloudMid {
0% {
top: 10px;
left: 420px;
opacity: 0;
}
20% {
top: 40px;
left: 360px;
opacity: 1;
}
70% {
top: 130px;
left: 180px;
opacity: 1;
}
100% {
top: 160px;
left: 120px;
opacity: 0;
}
}
@keyframes cloudRight {
0% {
top: 100px;
left: 500px;
opacity: 0;
}
20% {
top: 120px;
left: 460px;
opacity: 1;
}
80% {
top: 180px;
left: 340px;
opacity: 1;
}
100% {
top: 200px;
left: 300px;
opacity: 0;
}
}
}
}
.bullshit {
position: relative;
float: left;
width: 300px;
padding: 30px 0;
overflow: hidden;
&__oops {
font-size: 32px;
font-weight: bold;
line-height: 40px;
color: #1482f0;
opacity: 0;
margin-bottom: 20px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
&__headline {
font-size: 20px;
line-height: 24px;
color: #222;
font-weight: bold;
opacity: 0;
margin-bottom: 10px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.1s;
animation-fill-mode: forwards;
}
&__info {
font-size: 13px;
line-height: 21px;
color: grey;
opacity: 0;
margin-bottom: 30px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.2s;
animation-fill-mode: forwards;
}
&__return-home {
display: block;
float: left;
width: 110px;
height: 36px;
background: #1482f0;
border-radius: 100px;
text-align: center;
color: #ffffff;
opacity: 0;
font-size: 14px;
line-height: 36px;
cursor: pointer;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.3s;
animation-fill-mode: forwards;
}
@keyframes slideUp {
0% {
transform: translateY(60px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
}
}
</style>
<template>
<div style="width: 100vw;height: 100vh;">创建</div>
</template>
<script setup>
</script>
\ No newline at end of file
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path';
import AutoImport from 'unplugin-auto-import/vite';
// https://vite.dev/config/
export default defineConfig({
plugins: [vue(),
AutoImport({
dts: './auto-imports.d.ts', // 项目根目录生成auto-imports.d.ts配置文件
imports: ["vue", "vue-router", "pinia",] // 设置自动导入的模块/插件(不用开发时每次都引入生命周期才能用)
})
],
//设置路径
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
server: {
port: 80,//指定开发服务器的端口
// host: true,//指定开发度武器的主机名
host: '0.0.0.0',//开发服务器将监听所有可用的网络地址(包括局域网和本地网络)
open: true,//自动在默认浏览器上打开
proxy: {
'/api': {
target: 'http://172.16.13.11:32089', //test----------------------尾部214,2,31,12,11都可以,登不上时换个试试
// target: 'http://172.16.34.76:18088',
ws: false,//代理websocked
changeOrigin: true, //是否跨域
secure: true, //是否https接口
rewrite: (path) => path.replace(/^\/api/, ""),//重写请求路径,使用正则表达式将请求路径中的 /dev-api 前缀替换为空字符串。例如,/dev-api/users 将被重写为 /users,然后代理到目标服务器。
},
'/wss': {
target: 'ws://172.16.13.11:32089/ws/vision',//text
// target: 'ws://172.16.34.76:18088/ws/vision',
ws: true,//代理websocked
changeOrigin: true, //是否跨域
secure: false, //是否https接口
rewrite: (path) => path.replace(/^\/wss/, ""),
},
'/ety': {
target: 'ws://172.16.13.11:32089',//text
// target: 'ws://172.16.34.76:18088/ws/vision',
ws: true,//代理websocked
changeOrigin: true, //是否跨域
secure: false, //是否https接口
rewrite: (path) => path.replace(/^\/ety/, ""),
},
}
},
})
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论