提交 2f298568 authored 作者: Administrator's avatar Administrator

更新依赖,去除冗余代码

上级 87c17e4a
# 开发环境
VITE_APP_TITLE = "星云平台测试"
VITE_APP_PORT = 3003
# 请求接口
# 开发环境
VITE_APP_TITLE = "Lic管理系统"
VITE_APP_PORT = 3003
# 请求接口
VITE_APP_BASE_URL = "lic"
\ No newline at end of file
#生产环境
VITE_APP_TITLE = "星云平台"
VITE_APP_PORT = 3002
# 请求接口
VITE_APP_BASE_URL = "lic"
#生产环境
VITE_APP_TITLE = "Lic平台"
VITE_APP_PORT = 3002
# 请求接口
VITE_APP_BASE_URL = "lic"
# starbos-ui
#### Description
星支平台前端框架,
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme_XXX.md to support different languages, such as Readme_en.md, Readme_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
# starbos-ui
#### 介绍
星云平台前端框架,基于vite +vue3.0+typescript+element-plus开发
## 项目安装
```
yarn install
```
### 项目编译及启动
```
yarn dev
```
### 编译部署
```
yarn build
```
### 行格式化
```
yarn lint
```
### 自定义配置
See [Configuration Reference](https://cli.vuejs.org/config/).
# starbos-ui
#### 介绍
Lic 平台前端框架,基于 vite +vue3.0+typescript+element-plus 开发
## 项目安装
```
yarn install
```
### 项目编译及启动
```
yarn dev
```
### 编译部署
```
yarn build
```
### 行格式化
```
yarn lint
```
### 自定义配置
See [Configuration Reference](https://cli.vuejs.org/config/).
......@@ -3,3 +3,5 @@ services:
build:
context: ./
image: registry.lingqingkeji.com/lic-portal
ports:
- 8091:8091
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -8,39 +8,33 @@
"tsc": "vue-tsc --noEmit"
},
"dependencies": {
"@element-plus/icons-vue": "^1.1.4",
"@element-plus/icons-vue": "^2.0.10",
"axios": "^0.24.0",
"echarts": "^5.3.0",
"element-plus": "^2.1.11",
"element-plus": "^2.6.0",
"eslint": "^8.4.1",
"eslint-plugin-vue": "^8.2.0",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"nprogress": "^0.2.0",
"qs": "^6.10.3",
"socket.io-client": "^4.5.0",
"vue": "^3.2.33",
"vue": "^3.2.45",
"vue-demi": "^0.13.1",
"vue-i18n": "^9.1.10",
"vue-router": "4",
"vue-socket.io": "^3.0.10",
"vue3-cron": "^1.1.8",
"vue-router": "^4.1.6",
"vuex": "^4.0.2"
},
"devDependencies": {
"@types/lodash": "^4.14.182",
"@types/node": "^16.11.12",
"@types/node": "^18.11.18",
"@types/qs": "^6.9.7",
"@vitejs/plugin-vue": "^2.3.1",
"sass": "^1.86.0",
"typescript": "^4.4.3",
"unplugin-auto-import": "^0.7.1",
"@vitejs/plugin-vue": "^4.0.0",
"sass": "^1.57.1",
"terser": "^5.39.0",
"typescript": "^4.9.3",
"unplugin-auto-import": "^0.12.1",
"unplugin-icons": "^0.14.3",
"unplugin-vue-components": "^0.19.3",
"vite": "^2.6.14",
"unplugin-vue-components": "^0.22.12",
"vite": "^4.0.0",
"vite-plugin-inspect": "^0.5.0",
"vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "^0.3.0"
"vue-tsc": "^1.0.11"
},
"license": "ISC"
}
This source diff could not be displayed because it is too large. You can view the blob instead.
<!-- 此处注意,使用 v-model="visible"绑定的形式
上线会报错
修改为如下方式
:model-value="visible"
-->
<template>
<el-dialog
:title='title'
:model-value="visible"
:before-close="onClose"
append-to-body
:width="width + 'px'"
>
<div class="container" :style="{height:height + 'px'}">
<slot name="content"></slot>
</div>
<template #footer>
<span class="dialog-footer">
<el-button type='danger' @click="onClose">取消</el-button>
<el-button type="primary" @click="onConfirm">确定</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
const props = defineProps({
title: {//弹框标题
type: String,
default: '标题'
},
visible: { //控制弹框的展示和影藏
type: Boolean,
default: false
},
width: {
type: Number,
default: 600
},
height: {
type: Number,
default: 250
}
})
const emit = defineEmits(['onClose','onConfirm'])
//定义弹框的关闭
const onClose = () =>{
emit('onClose')
}
//定义弹框的确定
const onConfirm = () =>{
emit('onConfirm')
}
</script>
<style lang="scss" scope>
.container {
overflow-x: initial;
overflow-y: auto;
}
.el-dialog {
border-top-left-radius: 7px !important;
border-top-right-radius: 7px !important;
.el-dialog__header {
border-top-left-radius: 7px !important;
border-top-right-radius: 7px !important;
background-color: #1890ff !important;
.el-dialog__title {
color: #fff;
font-size: 16px;
font-weight: 600;
}
.el-dialog__close {
color: #fff;
}
}
.el-dialog__body {
padding: 10px;
}
.el-dialog__footer {
border-top: 1px solid #e8eaec !important;
padding: 10px;
}
}
</style>
\ No newline at end of file
<template>
<el-dialog
:title="title"
:model-value="visible"
:before-close="onClose"
append-to-body
:width="width + 'px'"
>
<div class="container" :style="{ height: height + 'px' }">
<slot name="content"></slot>
</div>
<template #footer>
<span class="dialog-footer">
<el-button type="danger" @click="onClose">取消</el-button>
<el-button type="primary" @click="onConfirm">确定</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
defineProps({
title: {
//弹框标题
type: String,
default: "标题",
},
visible: {
//控制弹框的展示和影藏
type: Boolean,
default: false,
},
width: {
type: Number,
default: 600,
},
height: {
type: Number,
default: 250,
},
});
const emit = defineEmits(["onClose", "onConfirm"]);
//定义弹框的关闭
const onClose = () => {
emit("onClose");
};
//定义弹框的确定
const onConfirm = () => {
emit("onConfirm");
};
</script>
<style lang="scss" scope>
.container {
overflow-x: initial;
overflow-y: auto;
}
.el-dialog {
border-top-left-radius: 7px !important;
border-top-right-radius: 7px !important;
.el-dialog__header {
border-top-left-radius: 7px !important;
border-top-right-radius: 7px !important;
background-color: #1890ff !important;
.el-dialog__title {
color: #fff;
font-size: 16px;
font-weight: 600;
}
.el-dialog__close {
color: #fff;
}
}
.el-dialog__body {
padding: 10px;
}
.el-dialog__footer {
border-top: 1px solid #e8eaec !important;
padding: 10px;
}
}
</style>
<template>
<div class="components-input-demo-presuffix">
<a-input
@click="openModal"
placeholder="corn表达式"
v-model="cron"
@change="handleOK"
>
<a-icon slot="prefix" type="schedule" title="corn控件" />
<a-icon
v-if="cron"
slot="suffix"
type="close-circle"
@click="handleEmpty"
title="清空"
/>
</a-input>
<JCronModal ref="innerVueCron" :data="cron" @ok="handleOK"></JCronModal>
</div>
</template>
<script>
import JCronModal from "@/components/corn/JCronModal.vue";
export default {
name: "JCron",
components: {
JCronModal,
},
props: {
value: {
required: false,
type: String,
default: "",
},
},
data() {
return {
cron: this.value,
};
},
watch: {
value(val) {
this.cron = val;
},
},
methods: {
openModal() {
this.$refs.innerVueCron.show();
},
handleOK(val) {
this.cron = val;
this.$emit("change", this.cron);
// this.$emit("change", Object.assign({}, this.cron));
},
handleEmpty() {
this.handleOK("");
},
},
model: {
prop: "value",
event: "change",
},
};
</script>
<style scoped>
.components-input-demo-presuffix .anticon-close-circle {
cursor: pointer;
color: #ccc;
transition: color 0.3s;
font-size: 12px;
}
.components-input-demo-presuffix .anticon-close-circle:hover {
color: #f5222d;
}
.components-input-demo-presuffix .anticon-close-circle:active {
color: #666;
}
</style>
差异被折叠。
<template>
<div>
<div ref="commonEchartRef" :style="{ height: height, width: width }"></div>
</div>
</template>
<script setup lang='ts'>
import { ref, onMounted, watchEffect } from 'vue'
import useEcharts from '@/hooks/useEcharts';
//接收父组件传递的参数
//withDefaults:设置默认值
const props = withDefaults(defineProps<{
width?: string,
height: string,
optios: any
}>(), {
width: '100%',
height: '360px'
})
//定义ref属性
const commonEchartRef = ref<HTMLElement>()
onMounted(() => {
//叹号:断定commonEchartRef.value存在
const { setOptions, resize } = useEcharts(commonEchartRef.value!)
watchEffect(() => {
setOptions(props.optios)
})
//自适应
window.addEventListener('resize', () => {
resize();
})
})
</script>
<style scoped lang='scss'>
</style>
\ No newline at end of file
<template>
<div style="margin-top: 20px;">
<el-pagination v-model:currentPage="pageData.pageNo" v-model:page-size="pageData.pageSize"
:page-sizes="[10, 15, 20]" :small="pageData.small" :disabled="pageData.disabled"
:background="pageData.background" layout="->, total, sizes, prev, pager, next, jumper" :total="total"
@size-change="handleSizeChange" hide-on-single-page @current-change="handleCurrentChange" />
</div>
</template>
<script setup lang='ts'>
let props = defineProps({
pageData: {
type: Object,
default: {
pageNo: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 10
},
small: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
background: {
type: String || Boolean,
default: '' || false
}
}
},
total: {
type: Number,
default: 0
}
})
let emits = defineEmits(['sizeChange', 'currentChange'])
// 新条数
const handleSizeChange = (val: number) => {
emits('sizeChange', val)
}
// // 新页数
const handleCurrentChange = (val: number) => {
emits('currentChange', val)
}
</script>
<style lang = "scss" scoped>
</style>
\ No newline at end of file
<template>
<div style="margin-top: 20px">
<el-pagination
v-model:currentPage="pageData.pageNo"
v-model:page-size="pageData.pageSize"
:page-sizes="[10, 15, 20]"
:small="pageData.small"
:disabled="pageData.disabled"
:background="pageData.background"
layout="->, total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
hide-on-single-page
@current-change="handleCurrentChange"
/>
</div>
</template>
<script setup lang="ts">
let props = defineProps({
pageData: {
type: Object,
default: {
pageNo: {
type: Number,
default: 1,
},
pageSize: {
type: Number,
default: 10,
},
small: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
background: {
type: String || Boolean,
default: "" || false,
},
},
},
total: {
type: Number,
default: 0,
},
});
let emits = defineEmits(["sizeChange", "currentChange"]);
// 新条数
const handleSizeChange = (val: number) => {
emits("sizeChange", val);
};
// // 新页数
const handleCurrentChange = (val: number) => {
emits("currentChange", val);
};
</script>
import {reactive} from 'vue'
import { DialogModel } from "@/type/BastType";
export default function useDialog(){
//定义弹框属性
const dialog = reactive<DialogModel>({
title:'',
visible:false,
width:630,
height:280
})
//展示
const onShow = () =>{
dialog.visible = true;
}
//关闭
const onClose = () =>{
dialog.visible =false;
}
//确定
const onConfirm = () =>{
dialog.visible = false;
}
return {
dialog,
onShow,
onClose,
onConfirm
}
}
\ No newline at end of file
import * as echarts from 'echarts'
export default function useEcharts(el:HTMLElement){
//初始化echarts
const echartsInstance = echarts.init(el);
//设置options
const setOptions = (options:any) =>{
echartsInstance.setOption(options)
}
//自适应监听
const resize = () =>{
echartsInstance.resize()
}
return{
setOptions,
resize
}
}
\ No newline at end of file
export default {
// 路由国际化
route: {
dashboard: '首页',
},
// 登录页面国际化
login: {
title: '星云管理系统',
username: '账号',
password: '密码'
}
}
\ No newline at end of file
export default {
// 路由国际化
route: {
dashboard: "首页",
},
// 登录页面国际化
login: {
title: "Lic管理系统",
username: "账号",
password: "密码",
},
};
<template>
<Menu></Menu>
</template>
<script setup lang="ts">
import Menu from '@/components/Menu.vue'
</script>
<style lang="scss" scoped>
</style>
\ No newline at end of file
<template>
<Menu></Menu>
</template>
<script setup lang="ts">
import Menu from "@/components/Menu.vue";
</script>
<template>
<div>
</div>
</template>
<script lang="ts">
export default {
setup () {
return {}
}
}
</script>
<style lang="scss" scoped>
</style>
\ No newline at end of file
<template>
<div></div>
</template>
<script lang="ts">
export default {
setup() {
return {};
},
};
</script>
<template>
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="item in tabs">{{item.meta.title}}</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script setup lang='ts'>
import { ref,watch,Ref} from 'vue'
import { useRoute,RouteLocationMatched } from 'vue-router';
//定义面包屑导航数据
const tabs :Ref<RouteLocationMatched[]> = ref([]);
const route = useRoute();
const getBredcurm = ()=>{
//获取所有有meta和title
let mached = route.matched.filter(item => item.meta && item.meta.title);
//判断第一个是否是首页,如果不是,构造一个
const first = mached[0];
if(first && first.path !== '/licInformation'){
//构造一个
mached = [{path: '/licInformation',meta:{title:'首页'}} as any].concat(mached);
}
//设置面包屑导航数据
tabs.value = mached;
}
getBredcurm();
//路由发生变化,重新获取面包屑导航数据
watch(()=>route.path,()=>getBredcurm());
</script>
<style scoped lang='scss'>
</style>
\ No newline at end of file
<template>
<el-breadcrumb separator="/">
<el-breadcrumb-item v-for="item in tabs">{{item.meta.title}}</el-breadcrumb-item>
</el-breadcrumb>
</template>
<script setup lang='ts'>
import { ref,watch,Ref} from 'vue'
import { useRoute,RouteLocationMatched } from 'vue-router';
//定义面包屑导航数据
const tabs :Ref<RouteLocationMatched[]> = ref([]);
const route = useRoute();
const getBredcurm = ()=>{
//获取所有有meta和title
let mached = route.matched.filter(item => item.meta && item.meta.title);
//判断第一个是否是首页,如果不是,构造一个
const first = mached[0];
if(first && first.path !== '/licInformation'){
//构造一个
mached = [{path: '/licInformation',meta:{title:'首页'}} as any].concat(mached);
}
//设置面包屑导航数据
tabs.value = mached;
}
getBredcurm();
//路由发生变化,重新获取面包屑导航数据
watch(()=>route.path,()=>getBredcurm());
</script>
<template>
<el-dropdown placement="bottom-start">
<span class="el-dropdown-link">
<el-avatar :size="45" fit="contain" :src="avatar" />
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="userInfo">个人信息</el-dropdown-item>
<el-dropdown-item @click="loginOut">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<script setup lang='ts'>
import useInstance from '@/hooks/useInstance';
import { cleanSession, getToken } from '@/utils/auth';
import {store} from '@/store/index'
import { ref, reactive } from 'vue'
import router from '@/router';
const { global } = useInstance()
const avatar = store.state.user.userAvatar
//退出登录
const loginOut = async () => {
window.location.href = "/#/login";
cleanSession();
// let confirm = await global.$myconfirm('确定退出登录吗?')
// if (confirm) {
// let parm = {
// token: getToken()
// }
// let res = await loginOutApi(parm)
// if (res && res.code == 200) {
// //跳到登录
// window.location.href = "/login";
// //清空session
// cleanSession();
// }
// }
}
//还原数据
// const restore = async () => {
// let confirm = await global.$myconfirm('确定还原数据吗?')
// if (confirm) {
// let res = await restoreApi();
// if (res && res.code == 200) {
// //信息提示
// global.$message({ message: res.message, type: 'success' })
// }
// }
// }
//跳转个人信息
const userInfo = async () => {
router.push({path:'/user'})
}
</script>
<style scoped lang='scss'>
</style>
\ No newline at end of file
<template>
<el-dropdown placement="bottom-start">
<span class="el-dropdown-link">
<el-avatar :size="45" fit="contain" :src="avatar" />
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="userInfo">个人信息</el-dropdown-item>
<el-dropdown-item @click="loginOut">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<script setup lang="ts">
import useInstance from "@/hooks/useInstance";
import { cleanSession, getToken } from "@/utils/auth";
import { store } from "@/store/index";
import { ref, reactive } from "vue";
import router from "@/router";
const { global } = useInstance();
const avatar = store.state.user.userAvatar;
//退出登录
const loginOut = async () => {
let confirm = await global.$lqconfirm("确定退出登录吗?");
if (confirm) {
//跳到登录
window.location.href = "/#/login";
//清空session
cleanSession();
}
};
//跳转个人信息
const userInfo = async () => {
router.push({ path: "/user" });
};
</script>
<template>
<MenuLogo class="layout-logo" v-if="!isCollapse"></MenuLogo>
<el-menu :default-active="activeIdex" class="el-menu-vertical-startbos" :collapse="isCollapse" @open="handleOpen"
@close="handleClose" background-color="#304156" router>
<MenuItem :menuList="menuList">
</MenuItem>
</el-menu>
</template>
<script setup lang="ts">
import { reactive, computed } from 'vue'
import { useRoute } from 'vue-router'
import { useStore } from '@/store/index'
import MenuItem from './MenuItem.vue'
import MenuLogo from '@/layout/menu/MenuLogo.vue'
// setup语法糖中 定义的数据和方法,直接可以在模板中使用,无需要 return
const store = useStore()
// store.commit('menu/setCollapse')
// store.dispatch('menu/getMenuList')
// store.getters['user/getPermissions']
//当前路由
const route = useRoute();
const activeIdex = computed(() => {
const { path } = route;
return path;
})
//菜单数据
const menuList = computed(() => {
return store.getters['menu/getMenuList']
})
// let menuList = reactive([
// {
// path: '/dashboard',
// component: "Layout",
// meta: {
// title: "首页",
// icon: "HomeFilled",
// roles: ["sys:manage"]
// },
// children: []
// },
// {
// path: "/system",
// component: "Layout",
// alwaysShow: true,
// name: "system",
// meta: {
// title: "系统管理",
// icon: "Menu",
// roles: ["sys:manage"],
// parentId: 0,
// },
// children: [
// {
// path: "/department",
// component: "/system/department/department",
// alwaysShow: false,
// name: "department",
// meta: {
// title: "机构管理",
// icon: "Platform",
// roles: ["sys:dept"],
// parentId: 17,
// },
// },
// {
// path: "/userList",
// component: "/system/User/UserList",
// alwaysShow: false,
// name: "userList",
// meta: {
// title: "用户管理",
// icon: "el-icon-s-custom",
// roles: ["sys:user"],
// parentId: 17,
// },
// },
// {
// path: "/roleList",
// component: "/system/Role/RoleList",
// alwaysShow: false,
// name: "roleList",
// meta: {
// title: "角色管理",
// icon: "el-icon-s-tools",
// roles: ["sys:role"],
// parentId: 17,
// },
// },
// {
// path: "/menuList",
// component: "/system/Menu/MenuList",
// alwaysShow: false,
// name: "menuList",
// meta: {
// title: "权限管理",
// icon: "el-icon-document",
// roles: ["sys:menu"],
// parentId: 17,
// },
// },
// ],
// },
// {
// path: "/goods",
// component: "Layout",
// alwaysShow: true,
// name: "goods",
// meta: {
// title: "商品管理",
// icon: "el-icon-document",
// roles: ["sys:goods"],
// parentId: 0,
// },
// children: [
// {
// path: "/goodCategory",
// component: "/goods/goodsCategory/goodsCategoryList",
// alwaysShow: false,
// name: "goodCategory",
// meta: {
// title: "商品分类",
// icon: "el-icon-document",
// roles: ["sys:goodsCategory"],
// parentId: 34,
// },
// },
// ],
// },
// {
// path: "/systenConfig",
// component: "Layout",
// alwaysShow: true,
// name: "systenConfig",
// meta: {
// title: "系统工具",
// icon: "el-icon-document",
// roles: ["sys:systenConfig"],
// parentId: 0,
// },
// children: [
// {
// path: "/document",
// component: "/system/config/systemDocument",
// alwaysShow: false,
// name: "http://42.193.158.170:8089/swagger-ui/index.html",
// meta: {
// title: "接口文档",
// icon: "el-icon-document",
// roles: ["sys:document"],
// parentId: 42,
// },
// },
// ],
// },
// ]);
const isCollapse = computed(() => {
// return store.getters['getCollapse']
return store.getters['menu/getCollapse']
})
const handleOpen = (key: string, keyPath: string[]) => {
// console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
// console.log(key, keyPath)
}
</script>
<style scoped>
@keyframes logoAnimation {
0% {
transform: scale(0);
}
50% {
transform: scale(1);
}
100% {
transform: scale(1);
}
}
.layout-logo {
animation: logoAnimation 1s ease-out;
}
.el-menu-vertical-startbos:not(.el-menu--collapse) {
width: 230px;
min-height: 400px;
}
.el-menu {
border-right: none;
}
:deep(.el-sub-menu .el-sub-menu__title) {
color: #f4f4f5 !important;
}
:deep(.el-menu .el-menu-item) {
color: #bfcbd9;
}
/* 菜单点中文字的颜色 */
:deep(.el-menu-item.is-active) {
color: #409eff !important;
}
/* 当前打开菜单的所有子菜单颜色 */
:deep(.is-opened .el-menu-item) {
background-color: #1f2d3d !important;
}
/* 鼠标移动菜单的颜色 */
:deep(.el-menu-item:hover) {
background-color: #001528 !important;
}
</style>
\ No newline at end of file
<template>
<MenuLogo class="layout-logo" v-if="!isCollapse"></MenuLogo>
<el-menu
:default-active="activeIdex"
class="el-menu-vertical-startbos"
:collapse="isCollapse"
background-color="#304156"
router
>
<MenuItem :menuList="menuList"> </MenuItem>
</el-menu>
</template>
<script setup lang="ts">
import { useStore } from "@/store/index";
import MenuItem from "./MenuItem.vue";
import MenuLogo from "@/layout/menu/MenuLogo.vue";
const store = useStore();
//当前路由
const route = useRoute();
const activeIdex = computed(() => {
const { path } = route;
return path;
});
//菜单数据
const menuList = computed(() => {
return store.getters["menu/getMenuList"];
});
const isCollapse = computed(() => {
return store.getters["menu/getCollapse"];
});
</script>
<style scoped>
@keyframes logoAnimation {
0% {
transform: scale(0);
}
50% {
transform: scale(1);
}
100% {
transform: scale(1);
}
}
.layout-logo {
animation: logoAnimation 1s ease-out;
}
.el-menu-vertical-startbos:not(.el-menu--collapse) {
width: 230px;
min-height: 400px;
}
.el-menu {
border-right: none;
}
:deep(.el-sub-menu .el-sub-menu__title) {
color: #f4f4f5 !important;
}
:deep(.el-menu .el-menu-item) {
color: #bfcbd9;
}
/* 菜单点中文字的颜色 */
:deep(.el-menu-item.is-active) {
color: #409eff !important;
}
/* 当前打开菜单的所有子菜单颜色 */
:deep(.is-opened .el-menu-item) {
background-color: #1f2d3d !important;
}
/* 鼠标移动菜单的颜色 */
:deep(.el-menu-item:hover) {
background-color: #001528 !important;
}
</style>
<template>
<div class="logo">
<img src="@/assets/logo.png" alt="logo" />
<span class="title">星云平台</span>
</div>
</template>
<script setup lang="ts">
</script>
<style lang="scss" scoped>
.logo {
background-color: #2b2f3a;
height: 50px;
border: none;
line-height: 50px;
display: flex;
align-items: center;
padding-left: 15px;
color: #fff;
img {
width: 32px;
height: 32px;
margin-right: 12px;
}
span {
font-weight: 600;
line-height: 50px;
font-size: 16px;
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
vertical-align: middle;
}
}
</style>
\ No newline at end of file
<template>
<div class="logo">
<img src="@/assets/logo.png" alt="logo" />
<span class="title">Lic管理系统</span>
</div>
</template>
<script setup lang="ts"></script>
<style lang="scss" scoped>
.logo {
background-color: #2b2f3a;
height: 50px;
border: none;
line-height: 50px;
display: flex;
align-items: center;
padding-left: 15px;
color: #fff;
img {
width: 32px;
height: 32px;
margin-right: 12px;
}
span {
font-weight: 600;
line-height: 50px;
font-size: 16px;
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
vertical-align: middle;
}
}
</style>
import { request } from "../config";
import qs from "qs";
const COMMON_PATH = "";
export function toLogin(
// account
data: { username: string; password: string; code: string }
) {
return request({
url: COMMON_PATH + "/auth/login",
method: "post",
data: qs.stringify(data),
});
}
// export function getCode(){
// return request({
// url: COMMON_PATH + "/auth/getCaptcha",
// method: 'get',
// })
// }
import { request } from "../config";
import qs from "qs";
const COMMON_PATH = "";
export function toLogin(
// account
data: { username: string; password: string; code: string }
) {
return request({
url: COMMON_PATH + "/auth/login",
method: "post",
data: qs.stringify(data),
});
}
import { reactive, ref } from "vue";
import { ElForm } from "element-plus";
import { LoginParm } from "@/services/types/user/userModel";
export default function useBaseLogin() {
//表单的ref属性
const loginFormRef = ref<InstanceType<typeof ElForm>>();
//表单绑定的数据
const loginModel = reactive<LoginParm>({
username: 'admin',
password: 'QWER111.',
code: ''
})
//表单验证规则
const rules = reactive({
account: [{
required: true,
trigger: 'change',
message: '请填写登录账户'
}],
password: [{
required: true,
trigger: 'change',
message: '请填写登录密码'
}],
code: [{
required: true,
trigger: 'change',
message: '请填写验证码'
}]
})
return {
loginModel,
rules,
loginFormRef
}
}
\ No newline at end of file
import { reactive, ref } from "vue";
import { ElForm } from "element-plus";
import { LoginParm } from "@/services/types/user/userModel";
export default function useBaseLogin() {
//表单的ref属性
const loginFormRef = ref<InstanceType<typeof ElForm>>();
//表单绑定的数据
const loginModel = reactive<LoginParm>({
username: "admin",
password: "123456",
code: "",
});
//表单验证规则
const rules = reactive({
account: [
{
required: true,
trigger: "change",
message: "请填写登录账户",
},
],
password: [
{
required: true,
trigger: "change",
message: "请填写登录密码",
},
],
code: [
{
required: true,
trigger: "change",
message: "请填写验证码",
},
],
});
return {
loginModel,
rules,
loginFormRef,
};
}
import { ref, onMounted } from 'vue'
import { getImagApi } from '@/services/api/user/userAPI';
import { ElNotification } from 'element-plus';
import {debounce} from '@/utils/debounce_throttle'
export default function useImage() {
//定义图片src
const imgSrc = ref('../../../../checkcode.png');
// 获取图片
//btoa 创建一个base64编码的字符串
const getImage = debounce(async () => {
await getImagApi().then(res => {
return res.data.data as string;
}).then(data => {
imgSrc.value = data;
}).catch((err) => {
ElNotification({
title:'获取验证码失败',
message:err.message,
type:'error',
})
})
},1000)
onMounted(() => {
getImage()
})
return {
imgSrc,
getImage
}
}
\ No newline at end of file
import { getImagApi } from "@/services/api/user/userAPI";
import { ElNotification } from "element-plus";
import { debounce } from "@/utils/debounce_throttle";
export default function useImage() {
//定义图片src
const imgSrc = ref("../../../../checkcode.png");
// 获取图片
//btoa 创建一个base64编码的字符串
const getImage = debounce(async () => {
await getImagApi()
.then((res) => {
return res.data.data as string;
})
.then((data) => {
imgSrc.value = data;
})
.catch((err) => {
ElNotification({
title: "获取验证码失败",
message: err.message,
type: "error",
});
});
}, 1000);
onMounted(() => {
getImage();
});
return {
imgSrc,
getImage,
};
}
import { ref,getCurrentInstance } from "vue";
import { LoginParm } from "@/services/types/user/userModel";
import { store } from "@/store";
import { ElNotification } from 'element-plus';
import router from '@/router/index'
export default function useLogin(loginModel: LoginParm) {
const { proxy } = getCurrentInstance() as any;
//登录提交
const login = async () => {
//表单验证
proxy.$refs.loginFormRef.validate(async (valid: boolean) => {
if (valid) {
loginState.value = true
store.dispatch('user/login', loginModel).then((res: any) => {
loginState.value = false
if (res.code == 200) {
ElNotification({
title:'登录成功',
message:'欢迎回来',
type:'success',
})
//跳转到首页
setTimeout(()=> {
router.push({ path: '/' })
},1500)
} else {
ElNotification({
title:'登陆失败',
message:res.msg,
type:'error',
})
}
}).catch((err) => {
loginState.value = false
ElNotification({
title:'登录失败',
message:err.message,
type:'error',
})
})
}
})
}
//登录状态
const loginState = ref(false)
return {
login,
loginState
}
}
\ No newline at end of file
import { ref, getCurrentInstance } from "vue";
import { LoginParm } from "@/services/types/user/userModel";
import { store } from "@/store";
import { ElNotification } from "element-plus";
import router from "@/router/index";
export default function useLogin(loginModel: LoginParm) {
const { proxy } = getCurrentInstance() as any;
const num = ref(0);
//登录提交
const login = async () => {
//表单验证
proxy.$refs.loginFormRef.validate(async (valid: boolean) => {
if (valid) {
loginState.value = true;
store
.dispatch("user/login", loginModel)
.then((res: any) => {
if (res.code == 200) {
ElNotification({
title: "登录成功",
message: "欢迎回来",
type: "success",
});
//跳转到首页
setTimeout(() => {
router.push({ path: "/" });
loginState.value = false;
}, 1000);
} else {
loginState.value = false;
num.value++;
ElNotification({
title: "登录失败",
message: res.msg,
type: "error",
});
}
})
.finally(() => {
loginState.value = false;
});
}
});
};
//登录状态
const loginState = ref(false);
return {
login,
num,
loginState,
};
}
/**
* 定义回调函数
* @author ERRUI
*/
class SocketService {
static instance: any = null;
/**
* 单例模式
*/
static get Instance() {
if (SocketService.instance) {
return SocketService.instance;
}
return (SocketService.instance = new SocketService());
}
// 和服务端连接的socket对象
ws: any = null;
// 存储回调函数
callBackMapping = {};
// 标识是否连接成功
connected = false;
// 记录重试的次数
sendRetryCount = 0;
// 重新连接尝试的次数
connectRetryCount = 0;
/**
* 心跳检测机制:20秒发一个检测消息过去
*/
sendFixHeart() {
let sendFixHeartTimer: any = null;
clearInterval(sendFixHeartTimer);
sendFixHeartTimer = setInterval(() => {
this.ws.send(JSON.stringify({}));
}, 20000);
}
/**
* websocket连接
*/
connect() {
// 连接服务器
if (!window.WebSocket) {
return console.log('您的浏览器不支持WebSocket');
}
this.ws = new WebSocket('ws://192.168.2.209:8100/api/starbos_auth/websocket/1/web');
// 连接成功的事件
this.ws.onopen = () => {
console.log('连接服务端成功了,ws状态是' + this.ws.readyState);
this.connected = true;
// 重置重新连接的次数
this.connectRetryCount = 0;
this.sendFixHeart();
};
// 当连接成功之后, 服务器关闭的情况 | 连接服务端失败
this.ws.onclose = () => {
if (this.connectRetryCount >= 10) {
this.ws.close();
console.log('重新连接服务器失败');
} else {
this.connected = false;
this.connectRetryCount++;
setTimeout(() => {
this.close();
this.connect();
console.log('连接服务端失败第' + this.connectRetryCount + '次,1秒后重试');
}, 1000);
}
};
// websocket连接错误
this.ws.onerror = function () {
console.log('Error,websocket连接错误');
};
}
send(data: any) {
// 判断此时此刻有没有连接成功
if (this.connected) {
this.sendRetryCount = 0;
this.ws.send(JSON.stringify(data));
} else {
this.sendRetryCount++;
setTimeout(() => {
this.send(data);
console.log('已经重新发送第:' + this.sendRetryCount + '次');
}, 1000);
}
}
/**
* 关闭websocket连接
*/
close() {
this.ws.close();
}
}
export default SocketService;
\ No newline at end of file
import { InjectionKey } from 'vue';
import { useStore as baseUseStore, createStore, Store } from 'vuex';
import menu, { MenuState } from '@/store/modules/menu'
import tabs, { TabsState } from '@/store/modules/tabs'
import user, { UserState } from '@/store/modules/user'
import table, { TableState } from "@/store/modules/table";
import socket, { SocketState } from '@/store/modules/socket';
import { StarbosStore } from './tools';
export type RootState = {
tabs: TabsState,
menu: MenuState,
user: UserState,
table: TableState,
socket: SocketState
}
//导入所有的模块
export const modules = {
tabs: tabs,
menu: menu,
user: user,
table: table,
socket: socket
}
export const key: InjectionKey<Store<RootState>> = Symbol()
export const store = createStore<RootState>({
modules
}) as StarbosStore
// 定义自己的 `useStore` 组合式函数
export function useStore() {
return baseUseStore(key) as StarbosStore
}
import { InjectionKey } from "vue";
import { useStore as baseUseStore, createStore, Store } from "vuex";
import menu, { MenuState } from "@/store/modules/menu";
import tabs, { TabsState } from "@/store/modules/tabs";
import user, { UserState } from "@/store/modules/user";
import table, { TableState } from "@/store/modules/table";
import { StarbosStore } from "./tools";
export type RootState = {
tabs: TabsState;
menu: MenuState;
user: UserState;
table: TableState;
};
//导入所有的模块
export const modules = {
tabs: tabs,
menu: menu,
user: user,
table: table,
};
export const key: InjectionKey<Store<RootState>> = Symbol();
export const store = createStore<RootState>({
modules,
}) as StarbosStore;
// 定义自己的 `useStore` 组合式函数
export function useStore() {
return baseUseStore(key) as StarbosStore;
}
import { getMenuListApi } from "@/services/api/menu/menuAPI";
import { RouteRecordRaw } from "vue-router";
import { ActionContext } from "vuex";
import { RootState } from "..";
import Layout from '@/layout/index.vue'
import { store } from '@/store'
const modules = import.meta.glob('../../views/**/*.vue')
//定义state
export type MenuState = {
count: number,
collapse: boolean,
//菜单
menuList: any;
}
export const state: MenuState = {
count: 0,
collapse: false,
menuList: [
{
path: '/licInformation',
component: "Layout",
meta: {
title: "首页",
icon: "HomeFilled",
roles: ["sys:manage"]
},
children: []
}
]
}
//定义mutations
export const mutations = {
setCount(state: MenuState, count: number) {
state.count = count;
},
//设置collapse
setCollapse: (state: MenuState, collapse: boolean) => {
state.collapse = collapse;
},
setMenuList: (state: MenuState, menuList: Array<RouteRecordRaw>) => {
state.menuList = state.menuList.concat(menuList)
},
reSetList: (state: MenuState, menuList: Array<RouteRecordRaw>) => {
state.menuList = state.menuList.concat(menuList)
}
}
//定义actions
export const actions = {
getMenuList({ commit }: ActionContext<MenuState, RootState>, router: any) {
return new Promise((resolve, reject) => {
getMenuListApi().then(res => {
/* res.data.forEach(item => {
if (item.meta.title === '部门') {
item.children = []
}
}) */
let accessedRoutes;
if (res.code == 200) {
//动态生成路由
accessedRoutes = filterAsyncRoutes(res.data, router);
//设置到menuList
commit('setMenuList', accessedRoutes)
}
//返回
resolve(accessedRoutes);
}).catch(error => {
reject(error)
})
})
}
}
export function filterAsyncRoutes(routes: RouteRecordRaw[], router: any) {
const res: Array<RouteRecordRaw> = [];
routes.forEach((route: any) => {
const tmp = { ...route }
const component = tmp.component;
if (route.component) {
if (component == 'Layout') {
tmp.component = Layout;
} else {
tmp.component = modules[`../../views${component}.vue`]
}
}
if (tmp.children) {
//递归
tmp.children = filterAsyncRoutes(tmp.children, router)
}
router.addRoute(tmp)
res.push(tmp)
})
return res;
}
//定义getters
export const getters = {
getCount(state: MenuState) {
return state.count;
},
//获取collapse
getCollapse: (state: MenuState) => {
return state.collapse;
},
getMenuList: (state: MenuState) => {
return state.menuList
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
\ No newline at end of file
import { getMenuListApi } from "@/services/api/menu/menuAPI";
import { RouteRecordRaw } from "vue-router";
import { ActionContext } from "vuex";
import { RootState } from "..";
import Layout from "@/layout/index.vue";
import { store } from "@/store";
const modules = import.meta.glob("../../views/**/*.vue");
//定义state
export type MenuState = {
count: number;
collapse: boolean;
//菜单
menuList: any;
};
export const state: MenuState = {
count: 0,
collapse: false,
menuList: [
{
path: "/licInformation",
component: "Layout",
meta: {
title: "Lic信息",
icon: "HomeFilled",
roles: ["sys:manage"],
},
children: [],
},
],
};
//定义mutations
export const mutations = {
setCount(state: MenuState, count: number) {
state.count = count;
},
//设置collapse
setCollapse: (state: MenuState, collapse: boolean) => {
state.collapse = collapse;
},
setMenuList: (state: MenuState, menuList: Array<RouteRecordRaw>) => {
state.menuList = state.menuList.concat(menuList);
},
reSetList: (state: MenuState, menuList: Array<RouteRecordRaw>) => {
state.menuList = state.menuList.concat(menuList);
},
};
//定义actions
export const actions = {
getMenuList({ commit }: ActionContext<MenuState, RootState>, router: any) {
return new Promise((resolve, reject) => {
getMenuListApi()
.then((res) => {
/* res.data.forEach(item => {
if (item.meta.title === '部门') {
item.children = []
}
}) */
let accessedRoutes;
if (res.code == 200) {
//动态生成路由
accessedRoutes = filterAsyncRoutes(res.data, router);
//设置到menuList
commit("setMenuList", accessedRoutes);
}
//返回
resolve(accessedRoutes);
})
.catch((error) => {
reject(error);
});
});
},
};
export function filterAsyncRoutes(routes: RouteRecordRaw[], router: any) {
const res: Array<RouteRecordRaw> = [];
routes.forEach((route: any) => {
const tmp = { ...route };
const component = tmp.component;
if (route.component) {
if (component == "Layout") {
tmp.component = Layout;
} else {
tmp.component = modules[`../../views${component}.vue`];
}
}
if (tmp.children) {
//递归
tmp.children = filterAsyncRoutes(tmp.children, router);
}
router.addRoute(tmp);
res.push(tmp);
});
return res;
}
//定义getters
export const getters = {
getCount(state: MenuState) {
return state.count;
},
//获取collapse
getCollapse: (state: MenuState) => {
return state.collapse;
},
getMenuList: (state: MenuState) => {
return state.menuList;
},
};
export default {
namespaced: true,
state,
mutations,
actions,
getters,
};
import { RootState } from "../index"
import { ActionContext } from "vuex"
//定义state类型
export type SocketState = {
data:string;
}
//定义state
export const state:SocketState = {
data:''
}
//定义mutations
export const mutations = {
setData(state:SocketState,data:string){
state.data = data
localStorage.setItem('socketData',data)
}
}
//定义actions
export const actions = {
}
//定义getters
export const getters = {
getData(state:SocketState){
return state.data
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
\ No newline at end of file
import { getTableList } from '@/services/api/customTable'
import { ref } from 'vue'
import { useRoute } from 'vue-router'
export function tableLogic(props: Readonly<any>) {
const tableData = ref([])
const apiKey: any = useRoute().meta.apiKey
const completeApi = props.tableConfigData.apiKey + props.tableConfigData.tableApi
function init() {
getTableList(completeApi ?? apiKey).then((res: any) => {
if (res.code === 200) {
console.log(res)
if (props.tableConfigData.dataKey) {
tableData.value = res.data[props.tableConfigData.dataKey]
} else {
tableData.value = res.data
}
}
})
}
init()
return {
tableData,
init
}
}
import { getTableList } from "@/services/api/customTable";
import { ref } from "vue";
import { useRoute } from "vue-router";
export function tableLogic(props: Readonly<any>) {
const tableData = ref([]);
const apiKey: any = useRoute().meta.apiKey;
const completeApi =
props.tableConfigData.apiKey + props.tableConfigData.tableApi;
function init() {
getTableList(completeApi ?? apiKey).then((res: any) => {
if (res.code === 200) {
if (props.tableConfigData.dataKey) {
tableData.value = res.data[props.tableConfigData.dataKey];
} else {
tableData.value = res.data;
}
}
});
}
init();
return {
tableData,
init,
};
}
差异被折叠。
interface Scope{
row: any;
$index: number;
cellIndex: number
}
export interface FormItem{
label: string;
prop: string;
type: '' | 'input' | 'radio' | 'select' | 'switch';
selectProp?: {
value: string;
label: string;
},
hidden?: boolean;
inputType?: string;
viewType?: 'field' | 'avater' | 'module', // 表格渲染 field直接渲染 avatar渲染头像 module自定义渲染
width?: string;
fixed?: 'left' | 'right',
sortable?: boolean
}
interface TableConfigData{
title: string;
tableTitle: FormItem[];
drawerformData: object;
rules?: {
[key:string]: {
required: boolean;
message: string;
trigger: 'blur';
}[]
};
btnObj: {
width: string;
isAdd: boolean;
isDelete: boolean;
},
apiKey?: string;
tableApi?: string;
dataKey?: string;
}
export { Scope, TableConfigData }
interface Scope {
row: any;
$index: number;
cellIndex: number;
}
export interface FormItem {
label: string;
prop: string;
type: "" | "input" | "radio" | "select" | "switch";
selectProp?: {
value: string;
label: string;
};
hidden?: boolean;
inputType?: string;
viewType?: "field" | "avater" | "module"; // 表格渲染 field直接渲染 avatar渲染头像 module自定义渲染
width?: string;
fixed?: "left" | "right";
sortable?: boolean;
}
interface TableConfigData {
title: string;
tableTitle: FormItem[];
drawerformData: object;
rules?: {
[key: string]: {
required: boolean;
message: string;
trigger: "blur";
}[];
};
btnObj: {
isAdd: boolean;
isDelete: boolean;
width?: string;
};
apiKey?: string;
tableApi?: string;
dataKey?: string;
}
export { Scope, TableConfigData };
export enum EditType{
ADD = '0', //代表新增
EDIT = '1' //代表编辑
}
//定义弹框的标题
export enum Title {
ADD = '新增',
EDIT = '编辑'
}
//弹框属性类型
export type DialogModel = {
title:string,
visible:boolean,
height:number,
width:number
}
//返回值类型
export interface Result<T = any> {
code: number;
msg: string;
data: T;
}
//返回的状态码
export enum StatusCode {
NoAuth = 600,//无权限
Success = 200 //返回成功
}
\ No newline at end of file
// Generated by 'unplugin-auto-import'
// We suggest you to commit this file into source control
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const createLogger: typeof import('vuex')['createLogger']
const createNamespacedHelpers: typeof import('vuex')['createNamespacedHelpers']
const createStore: typeof import('vuex')['createStore']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const EffectScope: typeof import('vue')['EffectScope']
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('vuex')['mapActions']
const mapGetters: typeof import('vuex')['mapGetters']
const mapMutations: typeof import('vuex')['mapMutations']
const mapState: typeof import('vuex')['mapState']
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']
......@@ -34,6 +45,7 @@ declare global {
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveDirective: typeof import('vue')['resolveDirective']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
......@@ -45,8 +57,13 @@ declare global {
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useLink: typeof import('vue-router')['useLink']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useStore: typeof import('vuex')['useStore']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
export {}
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
DropdownCheck: typeof import('./../components/dropdownCheck/dropdownCheck.vue')['default']
ElAlert: typeof import('element-plus/es')['ElAlert']
ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
......@@ -30,8 +34,8 @@ declare module '@vue/runtime-core' {
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
......@@ -41,13 +45,19 @@ declare module '@vue/runtime-core' {
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload']
Form: typeof import('./components/Form.vue')['default']
InputTable: typeof import('./../components/inputTable/index.vue')['default']
MyForm: typeof import('./../components/form/MyForm.vue')['default']
Pagination: typeof import('./../components/pagination/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SvgIcon: typeof import('./../components/SvgIcon/index.vue')['default']
SysDialog: typeof import('./../components/SysDialog.vue')['default']
}
export interface ComponentCustomProperties {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}
export {}
<template>
<el-dialog v-model="props.mirrorDialog" :title="title" width="30%" :before-close="handleClose">
<template #title>
<div style="display: flex; justify-content: flex-start; align-items: center;">
<div>{{ title }}</div>
<el-alert style="width: 50%; margin-left: 40px;" title="选择镜像名后才能选择版本号" type="warning"
:closable="false" />
</div>
</template>
<el-form ref="formRef" :model="formData" label-width="100px" :rules="rules">
<el-form-item prop="name" label="镜像名">
<el-select v-model="formData.name" placeholder="请选择镜像名" @change="handleServiceChange">
<el-option v-for="item in serviceList" :key="item.id" :label="item.name" :value="item.name" />
</el-select>
</el-form-item>
<el-form-item prop="contextPath" label="服务路径">
<el-input v-model="formData.contextPath" placeholder="请输入服务路径" />
</el-form-item>
<el-form-item prop="version" label="版本">
<el-select v-model="formData.id" :disabled="!versionList" placeholder="请填写对应镜像名选择版本"
@change="handleChange">
<el-option v-for="item in versionList" :key="item.id" :label="item.version" :value="item.id" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="onConfirm">确定</el-button>
</template>
</el-dialog>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { getImageService, getImageVersion } from '@/services/api/imageService/index';
const props = defineProps({
mirrorDialog: {
type: Boolean,
require: true
}
})
const emits = defineEmits(['update:mirrorDialog', 'mirrorData'])
const formData = ref({
id: '',
name: '',
contextPath: '',
version: '',
})
const versionList = ref([]) as any
const serviceList = ref([]) as any
const formRef = ref()
const title = ref('新增服务镜像')
const rules = ref({
name: [{ required: true, message: '请输入镜像名', trigger: 'blur' }],
// contextPath: [{ required: true, message: '请输入服务路径', trigger: 'blur' }],
})
const handleServiceChange = async () => {
if (formData.value.name) {
let imageId;
serviceList.value.map((item: any) => {
if (item.name == formData.value.name)
imageId = item.id
})
const res: any = await getImageVersion({ imageId })
if (res.code === 200) versionList.value = res.data
}
}
const handleChange = (e: any) => {
versionList.value.map((item: any) => {
if (item.id == e) {
formData.value.version = item.version
}
})
}
const initService = async () => {
const res: any = await getImageService({ pageSize: 100 })
if (res.code === 200) {
serviceList.value = res.data.records
}
}
const handleClose = () => {
formRef.value?.resetFields()
formData.value = {
id: '',
name: '',
contextPath: '',
version: '',
}
emits('update:mirrorDialog', false)
}
const onConfirm = () => {
formRef.value?.validate((valid: Boolean, fields: any) => {
if (valid) {
emits('mirrorData', formData.value)
} else {
console.log('error submit!', fields)
}
})
}
defineExpose({
formData,
title,
initService,
handleClose
})
</script>
<style lang = "scss" scoped>
</style>
\ No newline at end of file
<template>
<el-dialog
v-model="props.mirrorDialog"
:title="title"
width="30%"
:before-close="handleClose"
>
<template #title>
<div
style="display: flex; justify-content: flex-start; align-items: center"
>
<div>{{ title }}</div>
<el-alert
style="width: 50%; margin-left: 40px"
title="选择镜像名后才能选择版本号"
type="warning"
:closable="false"
/>
</div>
</template>
<el-form ref="formRef" :model="formData" label-width="100px" :rules="rules">
<el-form-item prop="name" label="镜像名">
<el-select
v-model="formData.name"
placeholder="请选择镜像名"
@change="handleServiceChange"
>
<el-option
v-for="item in serviceList"
:key="item.id"
:label="item.name"
:value="item.name"
/>
</el-select>
</el-form-item>
<el-form-item prop="contextPath" label="服务路径">
<el-input v-model="formData.contextPath" placeholder="请输入服务路径" />
</el-form-item>
<el-form-item prop="version" label="版本">
<el-select
v-model="formData.id"
:disabled="!versionList"
placeholder="请填写对应镜像名选择版本"
@change="handleChange"
>
<el-option
v-for="item in versionList"
:key="item.id"
:label="item.version"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="onConfirm">确定</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from "vue";
import {
getImageService,
getImageVersion,
} from "@/services/api/imageService/index";
const props = defineProps({
mirrorDialog: {
type: Boolean,
require: true,
},
});
const emits = defineEmits(["update:mirrorDialog", "mirrorData"]);
const formData = ref({
id: "",
name: "",
contextPath: "",
version: "",
});
const versionList = ref([]) as any;
const serviceList = ref([]) as any;
const formRef = ref();
const title = ref("新增服务镜像");
const rules = ref({
name: [{ required: true, message: "请输入镜像名", trigger: "blur" }],
// contextPath: [{ required: true, message: '请输入服务路径', trigger: 'blur' }],
});
const handleServiceChange = async () => {
if (formData.value.name) {
let imageId;
serviceList.value.map((item: any) => {
if (item.name == formData.value.name) imageId = item.id;
});
const res: any = await getImageVersion({ imageId });
if (res.code === 200) versionList.value = res.data;
}
};
const handleChange = (e: any) => {
versionList.value.map((item: any) => {
if (item.id == e) {
formData.value.version = item.version;
}
});
};
const initService = async () => {
const res: any = await getImageService({ pageSize: 100 });
if (res.code === 200) {
serviceList.value = res.data.records;
}
};
const handleClose = () => {
formRef.value?.resetFields();
formData.value = {
id: "",
name: "",
contextPath: "",
version: "",
};
emits("update:mirrorDialog", false);
};
const onConfirm = () => {
formRef.value?.validate((valid: Boolean, fields: any) => {
if (valid) {
emits("mirrorData", formData.value);
} else {
console.log("error submit!", fields);
}
});
};
defineExpose({
formData,
title,
initService,
handleClose,
});
</script>
<template>
<div class="app-container"></div>
</template>
<script lang="ts">
export default {
name: 'Index'
}
</script>
<style lang="scss">
</style>
<template>
<div class="router">
<el-row :gutter="5" style="margin-bottom:5px;">
<el-col :span="10">
<el-card>
<el-tabs v-model="activeName">
<el-tab-pane label="待办事项" name="0"></el-tab-pane>
<el-tab-pane label="已办事项" name="1"></el-tab-pane>
<el-tab-pane label="待阅事项" name="2"></el-tab-pane>
</el-tabs>
<el-empty description="无事项"/>
</el-card>
</el-col>
<el-col :span="14">
<el-card>
<el-tabs v-model="activeName2">
<el-tab-pane label="我发起的流程" name="0"></el-tab-pane>
<el-tab-pane label="我已审的流程" name="1"></el-tab-pane>
</el-tabs>
<el-empty description="无流程"/>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts">
import {ref,reactive} from 'vue'
const activeName = ref('0')
const activeName2 = ref('0')
const activeName3 = ref('0')
const missions = reactive<Array<any>>([
{
name:'任务A',
description:'您将要执行任务A,去前往中非国际***公司窃取目标数据',
client:'黄*林'
},
{
name:'任务B',
description:'去tx获取内部开发数据',
client:'马*特'
}
])
</script>
<style></style>
\ No newline at end of file
<template>
<el-dialog v-model="props.imageServiceDialog" :title="title" width="30%" :before-close="handleClose">
<el-form ref="formRef" :model="formData" label-width="100px" :rules="rules">
<el-form-item prop="name" label="镜像名">
<el-input v-model="formData.name" placeholder="请输入镜像名" />
</el-form-item>
<el-form-item prop="contextPath" label="服务路径">
<el-input v-model="formData.contextPath" placeholder="请输入服务路径" />
</el-form-item>
<el-form-item prop="describe" label="描述">
<el-input v-model="formData.describe" placeholder="请输入描述" type="textarea" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="onConfirm">确定</el-button>
</template>
</el-dialog>
</template>
<script setup lang='ts'>
import { ref } from 'vue'
import { ruleProps } from '../interface/index'
const props = defineProps({
imageServiceDialog: {
type: Boolean,
require: true
}
})
const emits = defineEmits(['update:imageServiceDialog', 'imageServiceData'])
const formData = ref<ruleProps>({
id: '',
name: '',
contextPath: '',
describe: '',
})
const formRef = ref()
const title = ref('新增服务镜像')
const rules = ref({
name: [{ required: true, message: '请输入镜像名', trigger: 'blur' }],
// contextPath: [{ required: true, message: '请输入服务路径', trigger: 'blur' }],
})
const handleClose = () => {
formRef.value?.resetFields()
formData.value = {
id: '',
name: '',
contextPath: '',
describe: '',
}
emits('update:imageServiceDialog', false)
}
const onConfirm = () => {
formRef.value?.validate((valid: Boolean, fields: any) => {
if (valid) {
emits('imageServiceData', formData.value)
} else {
console.log('error submit!', fields)
}
})
}
defineExpose({
formData,
title
})
</script>
<style lang = "scss" scoped>
</style>
\ No newline at end of file
<template>
<el-dialog
v-model="props.imageServiceDialog"
:title="title"
width="30%"
:before-close="handleClose"
>
<el-form ref="formRef" :model="formData" label-width="100px" :rules="rules">
<el-form-item prop="name" label="镜像名">
<el-input v-model="formData.name" placeholder="请输入镜像名" />
</el-form-item>
<el-form-item prop="contextPath" label="服务路径">
<el-input v-model="formData.contextPath" placeholder="请输入服务路径" />
</el-form-item>
<el-form-item prop="describe" label="描述">
<el-input
v-model="formData.describe"
placeholder="请输入描述"
type="textarea"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="onConfirm">确定</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { ruleProps } from "../interface/index";
const props = defineProps({
imageServiceDialog: {
type: Boolean,
require: true,
},
});
const emits = defineEmits(["update:imageServiceDialog", "imageServiceData"]);
const formData = ref<ruleProps>({
id: "",
name: "",
contextPath: "",
describe: "",
});
const formRef = ref();
const title = ref("新增服务镜像");
const rules = ref({
name: [{ required: true, message: "请输入镜像名", trigger: "blur" }],
// contextPath: [{ required: true, message: '请输入服务路径', trigger: 'blur' }],
});
const handleClose = () => {
formRef.value?.resetFields();
formData.value = {
id: "",
name: "",
contextPath: "",
describe: "",
};
emits("update:imageServiceDialog", false);
};
const onConfirm = () => {
formRef.value?.validate((valid: Boolean, fields: any) => {
if (valid) {
emits("imageServiceData", formData.value);
} else {
console.log("error submit!", fields);
}
});
};
defineExpose({
formData,
title,
});
</script>
<template>
<div class='app-container' v-loading="loading">
<el-button type="primary" icon="plus" style="margin-bottom: 10px;" @click="addData">
新增服务镜像</el-button>
<el-table :data="tableData" border stripe>
<el-table-column v-for="(item, i ) in labelList" :key="i" :label="item.label" :prop="item.prop"
align="center" />
<el-table-column label="操作" align="center" width="255" fixed="right">
<template #default="scope">
<el-button link type="primary" size="small" @click="imageVersion(scope.row.id)">服务镜像版本
</el-button>
<el-divider direction="vertical" />
<el-button link type="primary" size="small" @click="editData(scope.row)">编辑
</el-button>
<el-divider direction="vertical" />
<el-button link type="danger" size="small" @click="deleteData(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination :page-data="listQuery" :total="listQuery.total" @size-change="sizeChange"
@current-change="currentChange" />
</div>
<image-service-form ref="imageServiceFormRef" v-model:image-service-dialog="imageServiceDialog"
@image-service-data="getImageServiceData" />
<image-service-table ref="imageVersionRef" v-model:image-version-table-dialog="imageVersionTableDialog" />
</template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
import { ruleProps } from './interface/index'
import {
getImageService,
addImageService,
updateImageService,
deleteImageService
} from '@/services/api/imageService/index';
import { ElMessage, ElMessageBox } from 'element-plus';
import imageServiceForm from './components/imageServiceForm.vue';
import imageServiceTable from './components/imageServiceTable.vue';
import pagination from '@/components/pagination/index.vue'
const labelList = [
{ label: '镜像名', prop: 'name' },
{ label: '服务路径', prop: 'contextPath' },
{ label: '描述', prop: 'describe' },
]
const imageServiceDialog = ref(false)
const imageVersionTableDialog = ref(false)
const loading = ref(true)
const imageServiceFormRef = ref()
const imageVersionRef = ref()
const tableData = ref<ruleProps[]>()
const listQuery = reactive({
pageNo: 1,
pageSize: 10,
total: 0
})
// 每页新条数
const sizeChange = (val: number) => {
listQuery.pageSize = val
init()
}
// 新页数
const currentChange = (val: number) => {
listQuery.pageNo = val
init()
}
const imageVersion = (id: number) => {
imageVersionRef.value.imageVersionId = id
imageVersionRef.value.initVersion(id)
imageVersionTableDialog.value = true
}
const addData = () => {
imageServiceFormRef.value.title = '新增服务镜像';
imageServiceDialog.value = true;
}
const editData = (row: any) => {
imageServiceFormRef.value.formData = row
imageServiceFormRef.value.title = '编辑服务镜像'
imageServiceDialog.value = true
}
const deleteData = (id: number) => {
ElMessageBox.confirm('确定删除吗?', '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const res: any = await deleteImageService(id)
if (res.code === 200) {
ElMessage.success('删除成功')
init()
}
})
}
const getImageServiceData = async (formData: ruleProps) => {
if (!formData.id) {
const res: any = await addImageService(formData)
if (res.code === 200) {
ElMessage.success('添加成功')
init()
imageServiceDialog.value = false
}
} else {
const res: any = await updateImageService(formData)
if (res.code === 200) {
ElMessage.success('修改成功')
imageServiceDialog.value = false
init()
}
}
}
const init = async () => {
loading.value = true
const res: any = await getImageService(listQuery)
if (res.code === 200) {
loading.value = false
tableData.value = res.data.records
listQuery.total = res.data.total
}
}
init()
</script>
<style lang = "scss" scoped>
</style>
\ No newline at end of file
<template>
<div class="app-container" v-loading="loading">
<el-button
type="primary"
icon="plus"
style="margin-bottom: 10px"
@click="addData"
>
新增服务镜像</el-button
>
<el-table :data="tableData" border stripe>
<el-table-column
v-for="(item, i) in labelList"
:key="i"
:label="item.label"
:prop="item.prop"
align="center"
/>
<el-table-column label="操作" align="center" width="255" fixed="right">
<template #default="scope">
<el-button
link
type="primary"
size="small"
@click="imageVersion(scope.row.id)"
>服务镜像版本
</el-button>
<el-divider direction="vertical" />
<el-button
link
type="primary"
size="small"
@click="editData(scope.row)"
>编辑
</el-button>
<el-divider direction="vertical" />
<el-button
link
type="danger"
size="small"
@click="deleteData(scope.row.id)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<pagination
:page-data="listQuery"
:total="listQuery.total"
@size-change="sizeChange"
@current-change="currentChange"
/>
</div>
<image-service-form
ref="imageServiceFormRef"
v-model:image-service-dialog="imageServiceDialog"
@image-service-data="getImageServiceData"
/>
<image-service-table
ref="imageVersionRef"
v-model:image-version-table-dialog="imageVersionTableDialog"
/>
</template>
<script setup lang="ts">
import { ref, reactive } from "vue";
import { ruleProps } from "./interface/index";
import {
getImageService,
addImageService,
updateImageService,
deleteImageService,
} from "@/services/api/imageService/index";
import { ElMessage, ElMessageBox } from "element-plus";
import imageServiceForm from "./components/imageServiceForm.vue";
import imageServiceTable from "./components/imageServiceTable.vue";
import pagination from "@/components/pagination/index.vue";
const labelList = [
{ label: "镜像名", prop: "name" },
{ label: "服务路径", prop: "contextPath" },
{ label: "描述", prop: "describe" },
];
const imageServiceDialog = ref(false);
const imageVersionTableDialog = ref(false);
const loading = ref(true);
const imageServiceFormRef = ref();
const imageVersionRef = ref();
const tableData = ref<ruleProps[]>();
const listQuery = reactive({
pageNo: 1,
pageSize: 10,
total: 0,
});
// 每页新条数
const sizeChange = (val: number) => {
listQuery.pageSize = val;
init();
};
// 新页数
const currentChange = (val: number) => {
listQuery.pageNo = val;
init();
};
const imageVersion = (id: number) => {
imageVersionRef.value.imageVersionId = id;
imageVersionRef.value.initVersion(id);
imageVersionTableDialog.value = true;
};
const addData = () => {
imageServiceFormRef.value.title = "新增服务镜像";
imageServiceDialog.value = true;
};
const editData = (row: any) => {
imageServiceFormRef.value.formData = row;
imageServiceFormRef.value.title = "编辑服务镜像";
imageServiceDialog.value = true;
};
const deleteData = (id: number) => {
ElMessageBox.confirm("确定删除吗?", "温馨提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(async () => {
const res: any = await deleteImageService(id);
if (res.code === 200) {
ElMessage.success("删除成功");
init();
}
});
};
const getImageServiceData = async (formData: ruleProps) => {
if (!formData.id) {
const res: any = await addImageService(formData);
if (res.code === 200) {
ElMessage.success("添加成功");
init();
imageServiceDialog.value = false;
}
} else {
const res: any = await updateImageService(formData);
if (res.code === 200) {
ElMessage.success("修改成功");
imageServiceDialog.value = false;
init();
}
}
};
const init = async () => {
loading.value = true;
const res: any = await getImageService(listQuery);
if (res.code === 200) {
loading.value = false;
tableData.value = res.data.records;
listQuery.total = res.data.total;
}
};
init();
</script>
<template>
</template>
<script setup lang="ts">
</script>
<style lang="scss">
</style>
<template>
<div class="logincontainer">
<el-form
class="loginForm"
:model="loginModel"
ref="loginFormRef"
:rules="rules"
:inline="false"
>
<el-form-item>
<div class="loginTitle">星云管理系统</div>
</el-form-item>
<el-form-item prop="username">
<el-input
placeholder="请输入账户"
size="large"
v-model="loginModel.username"
>
<template #prefix>
<el-icon class="el-input__icon">
<component :is="'avatar'" />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
type="password"
size="large"
placeholder="请输入密码"
v-model="loginModel.password"
>
<template #prefix>
<el-icon class="el-input__icon">
<component :is="'lock'" />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="code">
<el-row :gutter="24">
<el-col :span="16">
<el-input
placeholder="请输入验证码"
size="large"
v-model="loginModel.code"
maxlength="4"
@keyup.enter.native="login"
spellcheck="false"
>
<template #prefix>
<el-icon class="el-input__icon">
<circle-check />
</el-icon>
</template>
</el-input>
</el-col>
<el-col :span="2"></el-col>
<el-col :span="4">
<img :src="imgSrc" @click="getImage" />
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<el-button
class="mybtn"
@click="login"
type="primary"
size="large"
:loading="loginState"
>登录</el-button
>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import useImage from "@/services/business/login/useImage";
import useBaseLogin from "@/services/business/login/useBaseLogin";
import useLogin from "@/services/business/login/useLogin";
//基础数据
const { loginModel, rules, loginFormRef } = useBaseLogin();
//验证码
const { imgSrc, getImage } = useImage();
//登录
const { login, loginState } = useLogin(loginModel);
</script>
<style scoped lang="scss">
.logincontainer {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-image: url("../../assets/login-background.jpg");
.loginForm {
height: 320px;
width: 400px;
border-radius: 10px;
padding: 20px 35px;
background-color: white;
box-shadow: 0 0 25px #cac6c6;
.loginTitle {
margin: 0 auto;
font-size: 24px;
font-weight: 600;
display: flex;
justify-content: center;
align-items: center;
}
.mybtn {
width: 100%;
}
.el-icon {
height: 2.8em;
margin-left: -5px;
}
}
}
</style>
<template>
<div class="logincontainer">
<el-form
class="loginForm"
:model="loginModel"
ref="loginFormRef"
:rules="rules"
:inline="false"
>
<el-form-item>
<div class="loginTitle">集成管理系统</div>
</el-form-item>
<el-form-item prop="username">
<el-input
placeholder="请输入账户"
size="large"
v-model="loginModel.username"
>
<template #prefix>
<el-icon class="el-input__icon">
<component :is="'avatar'" />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
type="password"
size="large"
placeholder="请输入密码"
v-model="loginModel.password"
>
<template #prefix>
<el-icon class="el-input__icon">
<component :is="'lock'" />
</el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="code">
<div class="code">
<el-input
placeholder="请输入验证码"
size="large"
v-model="loginModel.code"
maxlength="4"
@keyup.enter.native="toLogin"
spellcheck="false"
style="width: 249px !important"
>
<template #prefix>
<el-icon class="el-input__icon">
<circle-check />
</el-icon>
</template>
</el-input>
<img :src="imgSrc" @click="getImage" />
</div>
</el-form-item>
<el-form-item>
<el-button
class="mybtn"
@click="login"
type="primary"
size="large"
:loading="loginState"
>登录</el-button
>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import { watch } from "vue";
import useImage from "@/services/business/login/useImage";
import useBaseLogin from "@/services/business/login/useBaseLogin";
import useLogin from "@/services/business/login/useLogin";
//基础数据
const { loginModel, rules, loginFormRef } = useBaseLogin();
//验证码
const { imgSrc, getImage } = useImage();
//登录
const { login, loginState, num } = useLogin(loginModel);
const toLogin = () => {
if (!loginState.value) login();
};
watch(num, () => getImage(), { deep: true });
</script>
<style scoped lang="scss">
.logincontainer {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background-image: url("../../assets/login-background.jpg");
.loginForm {
height: 320px;
width: 400px;
border-radius: 10px;
padding: 20px 35px;
background-color: white;
box-shadow: 0 0 25px #cac6c6;
.loginTitle {
margin: 0 auto;
font-size: 24px;
font-weight: 600;
display: flex;
justify-content: center;
align-items: center;
}
.mybtn {
width: 100%;
}
.el-icon {
height: 2.8em;
margin-left: -5px;
}
.code {
width: 100%;
padding: 0 6px;
display: flex;
justify-content: space-between;
margin-bottom: 6px;
}
}
}
</style>
<template>
<div class="app-container">
<Custom-table
:tableConfigData="tableConfigData"
@handle-show="handleShow"
>
<template v-slot:drawer>
<el-form-item
v-for="(item, index) in tableConfigData.tableTitle"
:key="index"
:label="item.label"
:prop="item.prop"
>
<custom-form-item
v-model:modValue="tableConfigData.drawerformData[item.prop]"
:type="item.type"
:inputType="item.inputValue"
:options="tableData"
:selectProp="item.selectProp"
>
<template v-slot:radios>
<el-radio :label="0">一级菜单</el-radio>
<el-radio :label="1">子菜单</el-radio>
</template>
</custom-form-item>
</el-form-item>
</template>
</Custom-table>
</div>
</template>
<script lang="ts">
import { ref, Ref, reactive } from 'vue'
import { Scope } from '@/table/type'
import CustomFormItem from '@/table/components/edit.vue'
import { menuConfigData } from './tableConfigData/menuManage'
export default {
name: 'MenuManage',
components: {
'custom-form-item': CustomFormItem
},
setup() {
// 列表数据
const tableConfigData = reactive(menuConfigData)
const tableData: Ref<any[]> = ref([])
const handleShow = ref((params: { key: string, tableData: object[], scope?: Scope }) => {
tableData.value = params.tableData
const key = params.key
switch (key) {
case '新增':
tableConfigData.drawerformData = {
id: '',
type: 0,
title: '',
component: '',
path: '',
sortNo: 0,
apiKey: '',
parentId: '',
icon: '',
is_show: true
}
break
case '编辑': {
if (!params.scope) return false
const row = params.scope.row
tableConfigData.drawerformData = {
id: row.id,
type: row.type,
title: row.title,
component: row.component,
path: row.path,
sortNo: row.sortNo,
apiKey: row.apiKey,
parentId: row.parentId,
icon: row.icon,
is_show: row.is_show
}
break
}
}
})
return {
tableConfigData,
handleShow,
tableData
}
}
}
</script>
<style lang="scss">
</style>
<template>
<div class="app-container">
<Custom-table :tableConfigData="tableConfigData" @handle-show="handleShow">
<template v-slot:drawer>
<el-form-item
v-for="(item, index) in tableConfigData.tableTitle"
:key="index"
:label="item.label"
:prop="item.prop"
>
<custom-form-item
v-model:modValue="tableConfigData.drawerformData[item.prop]"
:type="item.type"
:inputType="item.inputValue"
:options="tableData"
:selectProp="item.selectProp"
>
<template v-slot:radios>
<el-radio :label="0">一级菜单</el-radio>
<el-radio :label="1">子菜单</el-radio>
</template>
</custom-form-item>
</el-form-item>
</template>
</Custom-table>
</div>
</template>
<script lang="ts">
import { ref, Ref, reactive } from "vue";
import { Scope } from "@/table/type";
import CustomFormItem from "@/table/components/edit.vue";
import { menuConfigData } from "./tableConfigData/menuManage";
export default {
name: "MenuManage",
components: {
"custom-form-item": CustomFormItem,
},
setup() {
// 列表数据
const tableConfigData: any = reactive(menuConfigData);
const tableData: Ref<any[]> = ref([]);
const handleShow = ref(
(params: { key: string; tableData: object[]; scope?: Scope }) => {
tableData.value = params.tableData;
const key = params.key;
switch (key) {
case "新增":
tableConfigData.drawerformData = {
id: "",
type: 0,
title: "",
component: "",
path: "",
sortNo: 0,
apiKey: "",
parentId: "",
icon: "",
is_show: true,
};
break;
case "编辑": {
if (!params.scope) return false;
const row = params.scope.row;
tableConfigData.drawerformData = {
id: row.id,
type: row.type,
title: row.title,
component: row.component,
path: row.path,
sortNo: row.sortNo,
apiKey: row.apiKey,
parentId: row.parentId,
icon: row.icon,
is_show: row.is_show,
};
break;
}
}
}
);
return {
tableConfigData,
handleShow,
tableData,
};
},
};
</script>
<template>
<div class="app-container">
<Custom-table
:tableConfigData="tableConfigData"
@handle-show="handleShow"
>
<template v-slot:tableButton="scope">
<el-button type="primary" size="small" @click="drawerData.handleShow(scope)">授权</el-button>
</template>
<template v-slot:drawer>
<el-form-item
v-for="(item, index) in editData"
:key="index"
:label="item.label"
:prop="item.prop"
>
<custom-form-item
v-model:modValue="tableConfigData.drawerformData[item.prop]"
:type="item.type"
:inputType="item.inputValue"
:options="tableData"
:selectProp="item.selectProp"
>
</custom-form-item>
</el-form-item>
</template>
</Custom-table>
<el-drawer
v-model="drawerData.drawerShow"
title="授权"
direction="rtl"
:before-close="drawerData.handleClose"
>
<el-tree ref="tree" :data="drawerData.treeData" node-key="key" :default-expand-all="true" :check-strictly="true" show-checkbox />
<el-button type="primary" @click="drawerData.onSubmit(ruleFormRef)">保存</el-button>
<el-button @click="drawerData.handleClose">取消</el-button>
</el-drawer>
</div>
</template>
<script lang="ts">
import { ref, Ref, reactive } from 'vue'
import { Scope } from '@/table/type'
import { roleConfigData } from './tableConfigData/roleManage'
import { getQueryRoleMenu, getQueryTreeList, saveRole } from '@/services/api/role/roleAPI'
import type { ElTree } from 'element-plus';
import { ElNotification } from 'element-plus'
export default {
name: 'MenuManage',
setup() {
// type: 编辑的输入类型不填表示不加入编辑功能 inputType: input类型
const tableConfigData = reactive(roleConfigData)
const editData: Ref<any[]> = ref([])
tableConfigData.tableTitle.forEach(item => {
if (item.type) {
editData.value.push(item)
}
})
const tableData: Ref<any[]> = ref([])
const handleShow = ref((params: { key: string, tableData: object[], scope?: Scope }) => {
tableData.value = params.tableData
const key = params.key
switch (key) {
case '新增':
tableConfigData.drawerformData = {
id: '',
roleCode: '',
roleName: '',
roleDesc: ''
}
break
case '编辑': {
if (!params.scope) return false
const row = params.scope.row
tableConfigData.drawerformData = {
id: row.id,
roleCode: row.roleCode,
roleName: row.roleName,
roleDesc: row.roleDesc
}
break
}
}
})
const tree = ref<InstanceType<typeof ElTree>>()
const permissionParams: { permissionIds: Array<any>, lastPermissionIds: Array<any>, roleId: string} = {
permissionIds: [],
lastPermissionIds: [],
roleId: ''
}
// 授权抽屉数据
const drawerData = reactive({
drawerShow: false,
treeData: [],
handleClose: () => {
drawerData.drawerShow = false
},
handleShow: (scope: Scope) => {
drawerData.drawerShow = true
permissionParams.roleId = scope.row.id
getQueryRoleMenu({ id: scope.row.id }).then((res: any) => {
if (res.code === 200) {
permissionParams.lastPermissionIds = res.data
tree.value!.setCheckedKeys(res.data as Node[], true)
}
})
},
onSubmit: () => {
permissionParams.permissionIds = tree.value!.getCheckedKeys(false)
saveRole(permissionParams).then((res: any) => {
if (res.code === 200) {
drawerData.handleClose()
ElNotification({
title: '温馨提示',
message: '保存成功!',
type: 'success'
})
}
})
}
})
getQueryTreeList().then((res: any) => {
if (res.code === 200) {
drawerData.treeData = res.data.treeList
}
})
return {
handleShow,
tableConfigData,
tableData,
editData,
drawerData,
tree
}
}
}
</script>
<style lang="scss">
</style>
<template>
<div class="app-container">
<Custom-table :tableConfigData="tableConfigData" @handle-show="handleShow">
<template v-slot:tableButton="scope">
<el-button
type="primary"
size="small"
@click="drawerData.handleShow(scope)"
>授权</el-button
>
</template>
<template v-slot:drawer>
<el-form-item
v-for="(item, index) in editData"
:key="index"
:label="item.label"
:prop="item.prop"
>
<custom-form-item
v-model:modValue="tableConfigData.drawerformData[item.prop]"
:type="item.type"
:inputType="item.inputValue"
:options="tableData"
:selectProp="item.selectProp"
>
</custom-form-item>
</el-form-item>
</template>
</Custom-table>
<el-drawer
v-model="drawerData.drawerShow"
title="授权"
direction="rtl"
:before-close="drawerData.handleClose"
>
<el-tree
ref="tree"
:data="drawerData.treeData"
node-key="key"
:default-expand-all="true"
:check-strictly="true"
show-checkbox
/>
<el-button type="primary" @click="drawerData.onSubmit()">保存</el-button>
<el-button @click="drawerData.handleClose">取消</el-button>
</el-drawer>
</div>
</template>
<script lang="ts">
import { ref, Ref, reactive } from "vue";
import { Scope } from "@/table/type";
import { roleConfigData } from "./tableConfigData/roleManage";
import {
getQueryRoleMenu,
getQueryTreeList,
saveRole,
} from "@/services/api/role/roleAPI";
import type { ElTree } from "element-plus";
import { ElNotification } from "element-plus";
export default {
name: "MenuManage",
setup() {
// type: 编辑的输入类型不填表示不加入编辑功能 inputType: input类型
const tableConfigData: any = reactive(roleConfigData);
const editData: Ref<any[]> = ref([]);
tableConfigData.tableTitle.forEach((item: any) => {
if (item.type) {
editData.value.push(item);
}
});
const tableData: Ref<any[]> = ref([]);
const handleShow = ref(
(params: { key: string; tableData: object[]; scope?: Scope }) => {
tableData.value = params.tableData;
const key = params.key;
switch (key) {
case "新增":
tableConfigData.drawerformData = {
id: "",
roleCode: "",
roleName: "",
roleDesc: "",
};
break;
case "编辑": {
if (!params.scope) return false;
const row = params.scope.row;
tableConfigData.drawerformData = {
id: row.id,
roleCode: row.roleCode,
roleName: row.roleName,
roleDesc: row.roleDesc,
};
break;
}
}
}
);
const tree = ref<InstanceType<typeof ElTree>>();
const permissionParams: {
permissionIds: Array<any>;
lastPermissionIds: Array<any>;
roleId: string;
} = {
permissionIds: [],
lastPermissionIds: [],
roleId: "",
};
// 授权抽屉数据
const drawerData = reactive({
drawerShow: false,
treeData: [],
handleClose: () => {
drawerData.drawerShow = false;
},
handleShow: (scope: Scope) => {
drawerData.drawerShow = true;
permissionParams.roleId = scope.row.id;
getQueryRoleMenu({ id: scope.row.id }).then((res: any) => {
if (res.code === 200) {
permissionParams.lastPermissionIds = res.data;
tree.value!.setCheckedKeys(res.data, true);
}
});
},
onSubmit: () => {
permissionParams.permissionIds = tree.value!.getCheckedKeys(false);
saveRole(permissionParams).then((res: any) => {
if (res.code === 200) {
drawerData.handleClose();
ElNotification({
title: "温馨提示",
message: "保存成功!",
type: "success",
});
}
});
},
});
getQueryTreeList().then((res: any) => {
if (res.code === 200) {
drawerData.treeData = res.data.treeList;
}
});
return {
handleShow,
tableConfigData,
tableData,
editData,
drawerData,
tree,
};
},
};
</script>
import { TableConfigData } from "@/table/type";
const roleConfigData: TableConfigData = {
title: '角色',
tableTitle: [
{
label: '角色编码',
prop: 'roleCode',
type: 'input'
},
{
label: '角色名称',
prop: 'roleName',
type: 'input'
},
{
label: '角色描述',
prop: 'roleDesc',
type: 'input',
inputType: 'textarea'
},
{
label: '创建时间',
prop: 'fdate',
type: ''
}
],
drawerformData: {
id: '',
roleCode: '',
roleName: '',
roleDesc: ''
},
rules: {
roleCode: [
{ required: true, message: '请输入角色编码', trigger: 'blur' }
],
roleName: [
{ required: true, message: '请输入角色名称', trigger: 'blur' }
]
},
btnObj: {
width: '200',
isAdd: true,
isDelete: true
},
apiKey: 'role',
tableApi: '/list',
dataKey: 'records'
}
export { roleConfigData }
import { TableConfigData } from "@/table/type";
const roleConfigData: TableConfigData = {
title: "角色",
tableTitle: [
{
label: "角色编码",
prop: "roleCode",
type: "input",
},
{
label: "角色名称",
prop: "roleName",
type: "input",
},
{
label: "角色描述",
prop: "roleDesc",
type: "input",
inputType: "textarea",
},
{
label: "创建时间",
prop: "fdate",
type: "",
},
],
drawerformData: {
id: "",
roleCode: "",
roleName: "",
roleDesc: "",
},
rules: {
roleCode: [{ required: true, message: "请输入角色编码", trigger: "blur" }],
roleName: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
},
btnObj: {
width: "200",
isAdd: true,
isDelete: true,
},
apiKey: "role",
tableApi: "/list",
dataKey: "records",
};
export { roleConfigData };
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// vite 提供的操作env配置变量的方法loadEnv
import { loadEnv } from "vite";
// nodejs写法,获取项目目录
import path from "path";
import { resolve } from "path";
//按需要加载
// import AutoImport from 'unplugin-auto-import/vite'
// import Components from 'unplugin-vue-components/vite'
// import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// import Icons from 'unplugin-icons/vite'
// import IconsResolver from 'unplugin-icons/resolver'
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import Icons from "unplugin-icons/vite";
import IconsResolver from "unplugin-icons/resolver";
import Inspect from "vite-plugin-inspect";
import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
const pathSrc = path.resolve(__dirname, "src");
// https://vitejs.dev/config/
const pathSrc = resolve(__dirname, "src/types");
export default ({ command, mode }) => {
const env = loadEnv(mode, process.cwd());
return defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), "src/assets/icons")],
// 指定symbolId格式
iconDirs: [resolve(process.cwd(), "src/assets/icons")],
symbolId: "icon-[dir]-[name]",
}),
// AutoImport({
// // Auto import functions from Vue, e.g. ref, reactive, toRef...
// // 自动导入 Vue 相关函数,如:ref, reactive, toRef 等
// imports: ['vue'],
// // Auto import functions from Element Plus, e.g. ElMessage, ElMessageBox... (with style)
// // 自动导入 Element Plus 相关函数,如:ElMessage, ElMessageBox... (带样式)
// resolvers: [
// ElementPlusResolver(),
// // Auto import icon components
// // 自动导入图标组件
// IconsResolver({
// prefix: 'Icon',
// }),
// ],
// dts: path.resolve(pathSrc, 'auto-imports.d.ts'),
// }),
AutoImport({
imports: ["vue", "vuex", "vue-router"],
// Components({
// resolvers: [
// // Auto register icon components
// // 自动注册图标组件
// IconsResolver({
// enabledCollections: ['ep'],
// }),
// // Auto register Element Plus components
// // 自动导入 Element Plus 组件
// ElementPlusResolver(),
// ],
// dts: path.resolve(pathSrc, 'components.d.ts'),
// }),
// Icons({
// autoInstall: true,
// }),
resolvers: [
ElementPlusResolver(),
IconsResolver({
prefix: "Icon",
}),
],
dts: resolve(pathSrc, "auto-imports.d.ts"),
}),
Components({
resolvers: [
// 自动注册图标组件
IconsResolver({
enabledCollections: ["ep"],
}),
// 自动导入 Element Plus 组件
ElementPlusResolver(),
],
dts: resolve(pathSrc, "components.d.ts"),
}),
Icons({
autoInstall: true,
}),
Inspect(),
],
// 服务器配置
......@@ -77,10 +58,6 @@ export default ({ command, mode }) => {
https: false, // 默认用http方式
open: true, // 在开发服务器启动时自动在浏览器中打开应用程序
proxy: {
// 代理配置
// 字符串简写写法
// '/foo': '',
// 选项写法
"/lic": {
target: "http://192.168.1.252:8090",
},
......@@ -91,7 +68,7 @@ export default ({ command, mode }) => {
},
resolve: {
alias: {
"@": pathSrc,
"@": "/src",
},
},
css: {
......@@ -100,10 +77,13 @@ export default ({ command, mode }) => {
scss: {
charset: false, //防止样式出现警告,中文
additionalData: '@use "@/assets/styles/global.scss";',
implementation: "sass-embedded",
silenceDeprecations: ["legacy-js-api"],
},
},
},
build: {
minify: "terser", // 默认压缩方式
// 分块打包配置
chunkSizeWarningLimit: 1500, // 分块打包,分解块,将大块分解成更小的块
rollupOptions: {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论