Browse Source

init

master
lichong 9 months ago
commit
566d2223ac
  1. 52
      api/main.py
  2. 25
      front/.gitignore
  3. 7
      front/README.md
  4. 12
      front/index.html
  5. 30
      front/package.json
  6. 9
      front/public/config.json
  7. 1
      front/public/vite.svg
  8. 20
      front/src/App.vue
  9. 11
      front/src/api/login.js
  10. 36
      front/src/api/user.js
  11. 3
      front/src/assets/css/base.css
  12. BIN
      front/src/assets/img/avatar.png
  13. BIN
      front/src/assets/img/login.jpg
  14. BIN
      front/src/assets/img/logo.jpg
  15. BIN
      front/src/assets/img/student.png
  16. BIN
      front/src/assets/img/teacher.png
  17. 71
      front/src/component/changeItem.vue
  18. 114
      front/src/component/table.vue
  19. 22
      front/src/main.js
  20. 40
      front/src/plugins/axios.js
  21. 44
      front/src/router/index.js
  22. 79
      front/src/style.css
  23. 19
      front/src/utils/nprogress.js
  24. 85
      front/src/views/home.vue
  25. 103
      front/src/views/login.vue
  26. 340
      front/src/views/user.vue
  27. 42
      front/vite.config.js

52
api/main.py

@ -0,0 +1,52 @@
from flask import Flask
from pymongo import MongoClient
app = Flask(__name__)
client = MongoClient("mongodb://localhost:27019/")
db = client["back"]
collection = db["users"]
# 测试
@app.route("/")
def hello():
return "Hello World!"
# 新增用户
@app.route("/insert")
def insert_data():
user = {"name": "John Doe", "age": 25, "city": "New York"}
collection.insert_one(user)
return "Data inserted successfully!"
# 查询用户
@app.route("/query")
def query_data():
users = collection.find()
result = ""
for user in users:
result += f"Name: {user['name']}, Age: {user['age']}, City: {user['city']}<br>"
return result
# 更新用户
@app.route("/update")
def update_data():
query = {"name": "John Doe"}
new_data = {"$set": {"age": 30, "city": "San Francisco"}}
collection.update_one(query, new_data)
return "Data updated successfully!"
# 删除用户
@app.route("/delete")
def delete_data():
query = {"name": "John Doe"}
collection.delete_one(query)
return "Data deleted successfully!"
if __name__ == "__main__":
app.run()

25
front/.gitignore

@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
package-lock.json
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

7
front/README.md

@ -0,0 +1,7 @@
# base
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).

12
front/index.html

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="zh">
<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" />
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

30
front/package.json

@ -0,0 +1,30 @@
{
"name": "base",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"axios": "^1.6.6",
"dayjs": "^1.11.10",
"element-plus": "^2.5.3",
"lodash": "^4.17.21",
"md5": "^2.3.0",
"nprogress": "^0.2.0",
"papaparse": "^5.4.1",
"qs": "^6.11.2",
"unplugin-auto-import": "^0.17.4",
"unplugin-vue-components": "^0.26.0",
"vue": "^3.3.11",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.6.2",
"vite": "^5.0.8"
}
}

9
front/public/config.json

@ -0,0 +1,9 @@
{
"title": "可视化预警平台",
"jianceduixiang1path": "@/assets/img/jianceduixiang1.gif",
"jianceduixiang2path": "@/assets/img/jianceduixiang2.jpg",
"jianceduixiang3path": "@/assets/img/jianceduixiang3.png",
"jianceduixiang4path": "@/assets/img/jianceduixiang4.png",
"jianceduixiang5path": "@/assets/img/jianceduixiang5.gif",
"jianceduixiang6path": "@/assets/img/jianceduixiang6.gif"
}

1
front/public/vite.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.1 19.7L8.8 19L9 18.6C7.1 18.1 6 17.3 6 17V14.8C7.3 15.4 8.8 15.8 10.6 16C11.3 15.2 12.2 14.5 13.1 14H12C9.6 14 7.3 13.4 6 12.5V9.6C7.5 10.4 9.6 11 12 11S16.5 10.5 18 9.6V12.4C17.7 12.6 17.4 12.8 17 13C18 13 19 13.2 20 13.6V7C20 4.8 16.4 3 12 3S4 4.8 4 7V17C4 18.8 6.4 20.3 9.7 20.8C9.5 20.5 9.3 20.1 9.1 19.7M12 5C15.9 5 18 6.5 18 7S15.9 9 12 9 6 7.5 6 7 8.1 5 12 5M17 18C17.6 18 18 18.4 18 19S17.6 20 17 20 16 19.6 16 19 16.4 18 17 18M17 15C14.3 15 11.9 16.7 11 19C11.9 21.3 14.3 23 17 23S22.1 21.3 23 19C22.1 16.7 19.7 15 17 15M17 21.5C15.6 21.5 14.5 20.4 14.5 19S15.6 16.5 17 16.5 19.5 17.6 19.5 19 18.4 21.5 17 21.5Z" /></svg>

After

Width:  |  Height:  |  Size: 702 B

20
front/src/App.vue

@ -0,0 +1,20 @@
<template>
<router-view />
</template>
<script>
export default {
name: "app",
data() {
return {};
},
async mounted() { },
methods: {
},
watch: {},
computed: {},
};
</script>
<style scoped></style>

11
front/src/api/login.js

@ -0,0 +1,11 @@
import _axios from "@/plugins/axios";
//登录、注册
export function loginFun(data) {
return _axios({
url: `/v1/login`,
method: "POST",
data,
});
}

36
front/src/api/user.js

@ -0,0 +1,36 @@
import _axios from "@/plugins/axios";
//增加用户
export function addUser(data) {
return _axios({
url: `/v1/addUser`,
method: "POST",
data,
});
}
//删除用户
export function delUser(data) {
return _axios({
url: `/v1/delUser`,
method: "POST",
data,
});
}
//修改用户
export function getUser(data) {
return _axios({
url: `/v1/updateUser`,
method: "POST",
data,
});
}
//查找用户
export function getUser(data) {
return _axios({
url: `/v1/getUser`,
method: "POST",
data,
});
}

3
front/src/assets/css/base.css

@ -0,0 +1,3 @@
body {
margin: 0;
}

BIN
front/src/assets/img/avatar.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
front/src/assets/img/login.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
front/src/assets/img/logo.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
front/src/assets/img/student.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
front/src/assets/img/teacher.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

71
front/src/component/changeItem.vue

@ -0,0 +1,71 @@
<template>
<el-form :inline="true" :disabled="formDisabled" :model="formData" label-suffix=":" label-width="100px">
<el-row>
<el-col v-for="(headerItem, headerIndex) in formHeader" :key="headerIndex" :span="8">
<el-form-item :label="headerItem.label" v-if="!(['time'].indexOf(headerItem.type) !== -1 && type === 'add')">
<template v-if="['select'].indexOf(headerItem.type) !== -1">
<el-select-v2 filterable v-model="formData[headerItem.inputValue]" multiple collapse-tags
collapse-tags-tooltip :options="headerItem.options" :placeholder="headerItem.label" style="width: 330px"
:max-collapse-tags="2" />
</template>
<template v-else-if="['time'].indexOf(headerItem.type) !== -1">
<el-date-picker v-model="formData[headerItem.inputValue]" type="datetime" :disabled="headerItem.disabled"
:placeholder="headerItem.label" format="YYYY/MM/DD HH:mm:ss" style="width: 330px" />
</template>
<template v-else-if="['switch'].indexOf(headerItem.type) !== -1">
<el-switch v-model="formData[headerItem.inputValue]" style="width: 330px"/>
</template>
<template v-else-if="['text', 'email', 'textarea', 'password'].indexOf(
headerItem.type
) !== -1
">
<el-input v-model="formData[headerItem.inputValue]" :placeholder="headerItem.label" :type="headerItem.type"
clearable :show-password="headerItem.type === 'password'" style="width: 330px" />
</template>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: "bug",
props: {
type: {
typeof: String,
default: () => {
return "";
},
},
formHeader: {
typeof: Array,
default: () => {
return [];
},
},
formData: {
typeof: Object,
default: () => {
return {};
},
},
formDisabled: {
typeof: Boolean,
default: () => {
return false;
},
},
},
components: {},
data() {
return {};
},
watch: {},
computed: {},
async mounted() { },
beforeUnmount() { },
methods: {},
};
</script>
<style scoped></style>

114
front/src/component/table.vue

@ -0,0 +1,114 @@
<template>
<el-table :ref="refName" :data="tableData" class="mainTable" show-overflow-tooltip>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column type="index" width="50">
<template #default="scope">
{{ scope.$index + 1 + pageSize * (currentPage - 1) }}
</template>
</el-table-column>
<el-table-column v-for="(headerItem, headerIndex) in tableHeader" :key="headerItem._id"
:min-width="headerItem.minWidth" :label="headerItem.label">
<template #default="scope">
<template v-if="headerItem.type === 'time'">
{{ $dayjs(scope.row[headerItem.prop]).format("YYYY-MM-DD HH:mm:ss") }}
</template>
<template v-else-if="headerItem.type === 'array'">
{{ $_.join(scope.row[headerItem.prop], ",") }}
</template>
<template v-else-if="headerItem.type === 'password'"> ****** </template>
<template v-else>
{{ scope.row[headerItem.prop] }}
</template>
</template>
</el-table-column>
<el-table-column fixed="right" align="center" label="Operations" width="110">
<template #default="scope">
<el-button link type="primary" text @click="detailInfo(scope.row)">
<el-icon>
<InfoFilled />
</el-icon>
</el-button>
<el-button link type="primary" text @click="editInfo(scope.row)">
<el-icon>
<Edit />
</el-icon>
</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination :current-page="currentPage" :page-size="pageSize" :page-sizes="pageSizes"
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange"
@current-change="handleCurrentChange" class="pagination" />
</template>
<script>
export default {
name: "app",
emits: ["detailInfo", "editInfo", "handleSizeChange", "handleCurrentChange"],
props: {
refName: {
typeof: String,
default: "table",
},
tableHeader: {
typeof: Array,
default: () => {
return [];
},
},
tableData: {
typeof: Array,
default: () => {
return [];
},
},
currentPage: {
typeof: Number,
default: 1,
},
pageSize: {
typeof: Number,
default: 20,
},
pageSizes: {
typeof: Number,
default: () => {
return [16, 50, 100, 200];
},
},
total: {
typeof: Number,
default: 0,
},
},
data() {
return {};
},
async mounted() { },
methods: {
detailInfo(item) {
this.$emit("detailInfo", item);
},
editInfo(item) {
this.$emit("editInfo", item);
},
handleSizeChange(sizeVal) {
this.$emit("handleSizeChange", sizeVal);
},
handleCurrentChange(currentSize) {
this.$emit("handleCurrentChange", currentSize);
},
},
watch: {},
computed: {},
};
</script>
<style scoped>
.mainTable {
height: calc(100vh - 208px);
width: 100%;
}
.pagination {
justify-content: right;
}
</style>

22
front/src/main.js

@ -0,0 +1,22 @@
import App from "./App.vue";
import { createApp } from "vue";
// 引入路由实例
import router from "@/router/index.js";
//全局引入lodash
import _ from "lodash";
//全局引入lodash
import dayjs from "dayjs";
// 引入css
import "@/assets/css/base.css";
//全局引入element-plus所有图标
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const app = createApp(App);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.config.globalProperties.$_ = _; //挂载到app实例上
app.config.globalProperties.$dayjs = dayjs; //挂载到app实例上
app
.use(router) //路由
app.mount("#app");

40
front/src/plugins/axios.js

@ -0,0 +1,40 @@
import axios from "axios";
import qs from "qs";
import router from "@/router/index.js";
let config = {
baseURL: "",
timeout: 600 * 1000,
withCredentials: true, // Check cross-site Access-Control
/* `paramsSerializer` `params`
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
// 'a[0]=b&a[1]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
// 'a[]=b&a[]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
// 'a=b&a=c'
*/
paramsSerializer: (params) => {
return qs.stringify(params, { arrayFormat: "indices" });
},
};
const _axios = axios.create(config);
_axios.interceptors.request.use(
(config) => {
return config;
},
(error) => {
return Promise.reject(error);
}
);
_axios.interceptors.response.use(
(response) => {
return Promise.resolve(response.data);
},
(error) => {
ElMessage.error(error.response.data.message);
return Promise.reject(error);
}
);
export default _axios;

44
front/src/router/index.js

@ -0,0 +1,44 @@
import { createRouter, createWebHistory } from "vue-router";
import { close, start } from "@/utils/nprogress";
import home from "../views/home.vue"
const routes = [
{
path: "/",
name: "home",
component: home,
redirect: "/bug",
children: [{
path: "bug",
name: "bug",
component: () => import("../views/bug.vue"),
},
{
path: "user",
name: "user",
component: () => import("../views/user.vue"),
},]
},
{
path: "/login",
name: "login",
component: () => import("../views/login.vue"),
},
{ name: "重定向", path: "/:catchAll(.*)", redirect: "/bug" },
];
// 创建路由实例
const router = createRouter({
history: createWebHistory(),
routes, //路由表
});
let witheRouter = ["login"];
router.beforeEach((pre, next) => {
if (witheRouter.indexOf(pre.name) !== -1) {
}
start();
});
router.afterEach(() => {
close();
});
export default router;

79
front/src/style.css

@ -0,0 +1,79 @@
:root {
font-family: Inter, 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: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

19
front/src/utils/nprogress.js

@ -0,0 +1,19 @@
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
NProgress.configure({
easing: 'ease', // 动画方式
speed: 1000, // 递增进度条的速度
showSpinner: false, // 是否显示加载ico
trickleSpeed: 200, // 自动递增间隔
minimum: 0.3, // 更改启动时使用的最小百分比
parent: 'body', //指定进度条的父容器
})
// 打开进度条
export const start = () => {
NProgress.start()
}
// 关闭进度条
export const close = () => {
NProgress.done()
}

85
front/src/views/home.vue

@ -0,0 +1,85 @@
<template>
<el-container>
<el-header class="appHeader">
<el-row>
<el-col :span="23" style="align-self: center">
<el-image style="width: 60px; height: 60px" :src="logoUrl" fit="contain" />
</el-col>
<el-col :span="1" style="align-self: center">
<el-dropdown>
<span> <el-avatar :src="teacherUrl" /> </span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="logout">退出</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-col>
</el-row>
</el-header>
<el-container>
<el-container>
<el-main class="appMain">
<router-view />
</el-main>
<el-footer class="appFooter">版权所有</el-footer>
</el-container>
</el-container>
</el-container>
</template>
<script>
import logo from "@/assets/img/logo.jpg";
import teacher from "@/assets/img/teacher.png";
import student from "@/assets/img/student.png";
export default {
name: "home",
data() {
return {
logoUrl: logo,
teacherUrl: teacher,
studentUrl: student,
userName: "",
};
},
async mounted() {
await this.init();
},
methods: {
async init() {
if (!localStorage.getItem("userId")) {
this.$router.push("/login");
}
this.userName = localStorage.getItem("userName")
},
async logout() {
localStorage.clear()
await this.init()
},
routerFun(route) {
this.$router.push(route);
},
},
watch: {},
computed: {},
};
</script>
<style scoped>
.appHeader {
background-color: #67c23a;
}
.appMain {
height: calc(100vh - 120px);
padding: 8px;
}
.appAside {
height: calc(100vh - 60px);
background-color: #eee;
}
.appFooter {
background-color: #eee;
}
</style>

103
front/src/views/login.vue

@ -0,0 +1,103 @@
<template>
<div class="loginMain">
<div class="login">
<el-card shadow="hover" style="width: 450px">
<template #header>
<div style="text-align: center">
<el-button class="button" text @click="regist = false">
登录
</el-button>
<el-button class="button" text @click="regist = true">
注册
</el-button>
</div>
</template>
<div>
<el-form :model="regForm" label-suffix=":">
<el-form-item label="账号">
<el-input v-model="regForm.name" placeholder="请输入账号" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="regForm.password" type="password" placeholder="请输入密码" show-password />
</el-form-item>
<el-form-item label="邮箱" v-if="regist">
<el-input v-model="regForm.email" placeholder="请输入邮箱" />
</el-form-item>
</el-form>
</div>
<template #footer>
<div style="text-align: center">
<el-button class="button" v-if="regist" @click="login">
注册
</el-button>
<el-button class="button" v-else @click="login"> 登录 </el-button>
</div>
</template>
</el-card>
</div>
</div>
</template>
<script>
import {
loginFun, //
} from "@/api/login";
import md5 from "md5"
export default {
name: "login",
components: {},
data() {
return {
regist: false,
regForm: {
name: "",
password: "",
email: "",
},
};
},
watch: {},
computed: {},
async mounted() {
await this.init();
},
beforeUnmount() { },
methods: {
dealForm() {
return {
regist: this.regist,
name: this.regForm.name,
password: md5(this.regForm.password),
email: this.regForm.email,
}
},
async init() { },
async login() {
let formData = this.dealForm()
let res = await loginFun(formData)
if (!res.hasError) {
ElMessage.success("登陆成功");
localStorage.setItem("userId", res.list._id)
localStorage.setItem("userName", res.list.name)
this.$router.push("/bug")
} else {
ElMessage.error(res.msg);
localStorage.clear()
}
},
},
};
</script>
<style scoped>
.loginMain {
background-image: url("@/assets/img/login.jpg");
background-size: 100% 100%;
height: 100vh;
width: 100vw;
}
.login {
padding-top: calc(50vh - 165px);
padding-left: calc(50vw - 225px);
}
</style>

340
front/src/views/user.vue

@ -0,0 +1,340 @@
<template>
<el-row style="margin: 0 0 8px 0">
<el-col :span="4">
<el-button icon="Plus" type="primary" @click="addUserData">
新增
</el-button>
<el-button icon="Delete" type="danger" @click="delUserData">
删除
</el-button>
<el-button icon="Refresh" type="info" @click="init({})" text>
刷新
</el-button>
</el-col>
<el-col :span="2">
<el-upload
:limit="1"
accept="text/csv"
:auto-upload="false"
:on-change="fileChange"
>
<template #trigger>
<el-button type="primary">文件上传</el-button>
</template>
<template #file> </template>
</el-upload>
</el-col>
<el-col :span="6">
<el-input
v-model="searchValue"
placeholder="Please input email"
@keyup.enter="searchId"
>
<template #append>
<el-button @click="searchId" icon="Search" />
</template>
</el-input>
</el-col>
</el-row>
<div v-loading="loading">
<vueTable
ref="userTableParent"
:refName="refName"
:tableHeader="tableHeader"
:tableData="tableData"
:currentPage="currentPage"
:pageSize="pageSize"
:pageSizes="pageSizes"
:total="total"
@detailInfo="detailInfo"
@editInfo="editInfo"
@handleSizeChange="handleSizeChange"
@handleCurrentChange="handleCurrentChange"
>
</vueTable>
</div>
<el-dialog
v-model="addDialog.show"
:title="addDialog.title"
width="80%"
draggable
:close-on-click-modal="formDisabled"
>
<changeItem
:formData="formData"
:formDisabled="formDisabled"
:type="addDialog.type"
:formHeader="formHeaderLocal"
>
</changeItem>
<template #footer v-if="!formDisabled">
<div class="dialog-footer">
<el-button @click="closeDialog(addDialog)" type="info" plain>
取消
</el-button>
<el-button type="primary" @click="submitAdd" plain> 提交 </el-button>
</div>
</template>
</el-dialog>
</template>
<script>
import md5 from "md5";
import Papa from "papaparse";
import vueTable from "../component/table.vue";
import changeItem from "../component/changeItem.vue";
import {
getUser, //user
addUser, //user
delUser, //user
} from "@/api/user";
export default {
name: "user",
components: { vueTable, changeItem },
data() {
return {
refName: "userTable",
loading: false,
tableHeader: [
{ prop: "name", label: "name" },
{ prop: "password", label: "password", type: "password" },
{ prop: "email", label: "email" },
{ prop: "loginTime", label: "loginTime", type: "time", minWidth: 120 },
{ prop: "create_at", label: "create_at", type: "time", minWidth: 120 },
{ prop: "update_at", label: "update_at", type: "time", minWidth: 120 },
],
tableData: [],
currentPage: 1,
pageSize: 16,
pageSizes: [16, 50, 100, 200],
total: 0,
addDialog: {
type: "add",
show: false,
title: "新增用户",
},
formData: {
name: "",
password: "",
email: "",
loginTime: "",
},
formHeader: [
{
type: "text",
label: "name",
inputValue: "name",
},
{
type: "password",
label: "password",
inputValue: "password",
},
{
type: "email",
label: "email",
inputValue: "email",
},
{
type: "switch",
label: "allowRegist",
inputValue: "allowRegist",
hidden: true,
},
{
type: "time",
disabled: true,
label: "loginTime",
inputValue: "loginTime",
},
{
type: "time",
disabled: true,
label: "create_at",
inputValue: "create_at",
},
{
type: "time",
disabled: true,
label: "update_at",
inputValue: "update_at",
},
],
formHeaderLocal: [],
formDisabled: false,
searchValue: "",
};
},
watch: {},
computed: {},
async mounted() {
await this.init();
},
beforeUnmount() {},
methods: {
async init(params = {}, isReload = true) {
if (isReload) {
this.searchValue = "";
}
this.loading = true;
let res = await getUser({
subType: "get",
returnData: [
"name",
"email",
"allowRegist",
"loginTime",
"create_at",
"update_at",
],
pageSize: this.pageSize,
currentPage: this.currentPage,
...params,
});
this.tableData = res.list;
this.total = res.count;
this.loading = false;
},
async addUserData() {
this.addDialog = {
type: "add",
show: true,
title: "新增用户",
};
this.formData = {};
this.formHeaderLocal = this.$_.reject(this.formHeader, { hidden: true });
this.formDisabled = false;
},
closeDialog(addDialog) {
addDialog.show = false;
},
async submitAdd() {
let subData = { subType: this.addDialog.type };
for (let i = 0; i < this.formHeader.length; i++) {
let elei = this.formHeader[i];
if (elei.type !== "time") {
subData[elei.inputValue] = this.formData[elei.inputValue];
}
if (elei.type === "select") {
subData[`${elei.inputValue}_str`] = this.$_.join(
this.formData[elei.inputValue],
","
);
}
}
if (this.addDialog.type === "edit") {
subData["_id"] = this.formData._id;
}
subData["password"] = md5(this.$_.trim(this.formData.password));
try {
let res = await addUser(subData);
ElMessage({
message: res.msg,
type: "success",
});
} catch (error) {
} finally {
this.closeDialog(this.addDialog);
await this.init();
}
},
async delUserData() {
let rowList =
this.$refs[`${this.refName}Parent`].$refs[
this.refName
].getSelectionRows();
let delData = [];
let delDispalyData = [];
for (let i = 0; i < rowList.length; i++) {
let elei = rowList[i];
delData.push(elei._id);
delDispalyData.push(`${elei.BugID}`);
}
ElMessageBox.confirm(`${delDispalyData.join("、")}`, "删除", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
}).then(async () => {
let res = await delUser({ subType: "del", ids: delData });
await this.init();
ElMessage({
message: res.msg,
type: "success",
});
});
},
detailInfo(item) {
this.addDialog = {
type: "info",
show: true,
title: `查看${item.name}`,
};
if (item.name !== "admin") {
this.formHeaderLocal = this.$_.reject(this.formHeader, {
hidden: true,
});
} else {
this.formHeaderLocal = this.$_.cloneDeep(this.formHeader);
}
this.formDisabled = true;
this.formData = item;
},
editInfo(item) {
this.addDialog = {
type: "edit",
show: true,
title: `编辑${item.name}`,
};
if (item.name !== "admin") {
this.formHeaderLocal = this.$_.reject(this.formHeader, {
hidden: true,
});
} else {
this.formHeaderLocal = this.$_.cloneDeep(this.formHeader);
}
this.formDisabled = false;
this.formData = { ...item };
},
async handleSizeChange(pageSize) {
this.pageSize = pageSize;
await this.init();
},
async handleCurrentChange(currentPage) {
this.currentPage = currentPage;
await this.init();
},
fileChange(file) {
let fileData = [];
let that = this;
Papa.parse(file.raw, {
complete: async (result) => {
for (let i = 1; i < result.data.length; i++) {
let elei = result.data[i];
fileData.push({
name: that.$_.trim(elei[4]),
password: md5(that.$_.trim(elei[4])),
email: that.$_.trim(elei[4]),
});
}
let fileDataLocal = that.$_.uniqBy(fileData, "name");
let res = await addUser({ subType: "multi", list: fileDataLocal });
await this.init();
ElMessage({
message: res.msg,
type: "success",
});
},
});
},
async searchId() {
if (this.$_.trim(this.searchValue)) {
await this.init({ email: this.searchValue }, false);
} else {
await this.init();
}
},
},
};
</script>
<style scoped></style>

42
front/vite.config.js

@ -0,0 +1,42 @@
// Plugins
import vue from "@vitejs/plugin-vue";
// Utilities
import { defineConfig } from "vite";
import { fileURLToPath, URL } from "node:url";
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
define: { "process.env": {} },
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
extensions: [".js", ".json", ".jsx", ".mjs", ".ts", ".tsx", ".vue"],
},
server: {
port: 3000,
proxy: {
"/v1": {
target: "http://127.0.0.1:7001/v1",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/v1/, ""),
},
},
},
build: {
sourcemap: true,
},
});
Loading…
Cancel
Save