后台管理第一次提交

This commit is contained in:
sa_10_0 2024-10-23 17:55:22 +08:00
commit 25a377d05c
33 changed files with 1114 additions and 0 deletions

30
.gitignore vendored Normal file
View File

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

3
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"recommendations": ["Vue.volar"]
}

33
README.md Normal file
View File

@ -0,0 +1,33 @@
# vue_project
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```

7
env.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
declare module '*.vue' {
import { defineComponent } from 'vue';
const component: ReturnType<typeof defineComponent>;
export default component;
}
declare module '*.js'

13
index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

6
package-lock.json generated Normal file
View File

@ -0,0 +1,6 @@
{
"name": "vue_project",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

33
package.json Normal file
View File

@ -0,0 +1,33 @@
{
"name": "vue_project",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build --force"
},
"dependencies": {
"@element-plus/icons-vue": "^2.3.1",
"axios": "^1.7.2",
"element-plus": "^2.7.5",
"mitt": "^3.0.1",
"querystring": "^0.2.1",
"vue": "^3.4.21",
"vue-router": "^4.3.3"
},
"devDependencies": {
"@tsconfig/node20": "^20.1.4",
"@types/node": "^20.12.5",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/tsconfig": "^0.5.1",
"npm-run-all2": "^6.1.2",
"sass": "^1.77.5",
"typescript": "~5.4.0",
"vite": "^5.2.8",
"vue-tsc": "^2.0.11"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

13
src/App.vue Normal file
View File

@ -0,0 +1,13 @@
<template>
<RouterView></RouterView>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>

BIN
src/assets/admin.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

16
src/assets/gloable.css Normal file
View File

@ -0,0 +1,16 @@
*{
margin: 0;
padding: 0;
}
html, body{
height:100%;
}
.ml-5{
margin-left: 5px;
}
.pd-10{
padding:10px 0;
}

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
src/img/Login/login_top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

37
src/layout/Manage.vue Normal file
View File

@ -0,0 +1,37 @@
<template>
<div style="height: 100vh">
<el-container style="min-height: 100%">
<!-- 侧边栏-->
<Aside/>
<!-- 主体-->
<el-container>
<!-- 头部-->
<el-header style="font-size: 12px; border-bottom:2px solid #ccc; line-height: 60px; height: 70px;">
<Header/>
</el-header>
<!-- 身体-->
<el-main>
<!-- 表示当前页面的子路由会在router-view里面展示-->
<router-view/>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script setup lang="ts">
import Aside from '@/layout/components/Aside.vue'
import Header from "@/layout/components/Header.vue";
</script>
<style>
</style>

View File

@ -0,0 +1,96 @@
<template>
<el-aside :width="sideWidth + 'px'" style="background-color: rgb(238, 241, 246); box-shadow: rgba(0, 21, 155, 0.35) 2px 0 6px">
<el-aside :style="AsideObj">
<el-menu
style="height: 100vh; overflow-x: hidden"
background-color="rgb(170, 113, 81)"
:collapse="isCollapse"
:collapse-transition="false"
text-color="#fff"
router
active-text-color="#ffd04b">
<div style="height: 80px; color: white; font-weight: bold;
display: flex; align-items: center; justify-content: center">
<img src="../../assets/logo.png" alt="" style="height: 30px">
<span style="margin-left: 5px" v-show="isShow">泠珑水阁管理系统</span>
</div>
<el-sub-menu index="1">
<template #title>
<el-icon><HomeFilled /></el-icon>
<span>用户管理</span>
</template>
<el-menu-item index="/UserManagement">
<el-icon><List /></el-icon>
<span slot="title">用户列表</span>
</el-menu-item>
<el-menu-item index="/PersonalCenter">
<el-icon><UserFilled /></el-icon>
<span slot="title">个人中心</span>
</el-menu-item>
</el-sub-menu>
<el-sub-menu index="2">
<template #title>
<el-icon><HomeFilled /></el-icon>
<span>商品管理</span>
</template>
<el-menu-item index="/AddProduct">
<el-icon><Menu /></el-icon>
<span slot="title">添加商品</span>
</el-menu-item>
<el-menu-item index="/MerchandiseCenter">
<el-icon><UserFilled /></el-icon>
<span slot="title">商品中心</span>
</el-menu-item>
</el-sub-menu>
</el-menu>
</el-aside>
</el-aside>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import { defineProps } from 'vue';
import emitter from '@/utils/emitter'
import router from '@/router';
import {List} from "@element-plus/icons-vue";
defineProps(['send-data'])
const showLog = ref(true)
const isCollapse = ref(false)
const isShow = ref(true)
const sideWidth = ref(200)
const AsideObj = ref({
width: '200px'
})
emitter.on('Aside', (value:any) => {
showLog.value = value
if(showLog.value){
AsideObj.value.width = '64px'
isCollapse.value = true
isShow.value = false
sideWidth.value = 64
}else{
AsideObj.value.width = '200px'
isCollapse.value = false
isShow.value = true
sideWidth.value = 200
}
})
</script>
<style scoped>
</style>

View File

@ -0,0 +1,148 @@
<!--<template>-->
<!-- <div style=" height: 70px; width: 1248px; display: flex;-->
<!-- justify-content: space-between; align-items: center;">-->
<!-- <div style=" display: flex; justify-content: center;-->
<!-- align-items: center; margin-left: 10px">-->
<!-- <el-icon @click="changeState" v-show="showLog" size="20px" style="margin-right: 10px"><Expand/></el-icon>-->
<!-- <el-icon @click="changeState" v-show="!showLog" size="20px" style="margin-right: 10px"><Fold /></el-icon>-->
<!-- <el-breadcrumb separator="/">-->
<!-- <el-breadcrumb-item :to="{ path: currentPath}">{{ strArr[0] }}</el-breadcrumb-item>-->
<!-- <el-breadcrumb-item><a :href="currentPath">{{ strArr[1] }}</a></el-breadcrumb-item>-->
<!-- </el-breadcrumb>-->
<!-- </div>-->
<!-- <div :style="{display: 'flex', justifyContent:'center', alignItems: 'center', marginRight: offset + 'px'}">-->
<!-- <el-avatar style="margin-right: 10px">-->
<!-- <img src="../assets/admin.jpg" alt="">-->
<!-- </el-avatar>-->
<!-- <el-dropdown style="cursor: pointer;" size="default">-->
<!-- <span class="el-dropdown-link" style="font-size: 16px; font-weight: bold;">-->
<!-- <span>{{ currentUser.username }}</span><el-icon class="el-icon&#45;&#45;right"><arrow-down /></el-icon>-->
<!-- </span>-->
<!-- <template #dropdown>-->
<!-- <el-dropdown-menu>-->
<!-- <el-dropdown-item @click="$router.push('/manage/person')">个人信息</el-dropdown-item>-->
<!-- <el-dropdown-item @click="logout">退出登录</el-dropdown-item>-->
<!-- </el-dropdown-menu>-->
<!-- </template>-->
<!-- </el-dropdown>-->
<!-- </div>-->
<!-- </div>-->
<!--</template>-->
<!--<script setup lang="ts">-->
<!--import {computed, onMounted, ref} from 'vue'-->
<!--import emitter from '@/utils/emitter'-->
<!--import { useRouter} from 'vue-router';-->
<!--import { ElMessage } from 'element-plus';-->
<!--import { pathInfo } from '@/store/pathInfo'-->
<!--const pathStore = pathInfo()-->
<!--const strArr = computed(() => pathStore.currentPathName.split('/'))-->
<!--const currentPath = computed(() => pathStore.currentPath)-->
<!--const router = useRouter()-->
<!--const offset = ref(20)-->
<!--const showLog = ref(false)-->
<!--const currentUser = ref('')-->
<!--onMounted(() => {-->
<!-- currentUser.value = JSON.parse(localStorage.getItem('user'))-->
<!--})-->
<!--const changeState = () => {-->
<!-- showLog.value = !showLog.value-->
<!-- emitter.emit('Aside', showLog.value)-->
<!-- if(showLog.value){-->
<!-- offset.value = -116-->
<!-- }else{-->
<!-- offset.value = 20-->
<!-- }-->
<!--}-->
<!--const logout = () => {-->
<!-- ElMessage({-->
<!-- message: '退出成功',-->
<!-- type: 'success'-->
<!-- })-->
<!-- router.push('/login')-->
<!-- localStorage.removeItem('user')-->
<!--}-->
<!--</script>-->
<!--<style scoped>-->
<!--:deep(.el-tooltip__trigger:focus-visible) {-->
<!-- outline: unset;-->
<!--}-->
<!--</style>-->
<template>
<div style=" height: 70px; width: 1248px; display: flex;
justify-content: space-between; align-items: center;">
<div style=" display: flex; justify-content: center;
align-items: center; margin-left: 10px">
<el-icon @click="changeState" v-show="showLog" size="20px" style="margin-right: 10px"><Expand/></el-icon>
<el-icon @click="changeState" v-show="!showLog" size="20px" style="margin-right: 10px"><Fold /></el-icon>
<el-breadcrumb separator="/">
<a-breadcrumb-item>{{route.name}}</a-breadcrumb-item>
</el-breadcrumb>
</div>
<div :style="{display: 'flex', justifyContent:'center', alignItems: 'center', marginRight: offset + 'px'}">
<el-avatar style="margin-right: 10px">
<img src="../../assets/admin.jpg" alt="">
</el-avatar>
<el-dropdown style="cursor: pointer;" size="default">
<span class="el-dropdown-link" style="font-size: 16px; font-weight: bold;">
<span>用户名称</span><el-icon class="el-icon--right"><arrow-down /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="$router.push('/PersonalCenter')">个人信息</el-dropdown-item>
<el-dropdown-item @click="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import emitter from '@/utils/emitter'
import {useRoute, useRouter} from "vue-router";
const router = useRouter();
const route = useRoute();
const offset = ref(20)
const showLog = ref(false)
const logout = () => {
router.push('/')
}
const changeState = () => {
showLog.value = !showLog.value
emitter.emit('Aside', showLog.value)
if(showLog.value){
offset.value = -116
}else{
offset.value = 20
}
}
</script>
<style scoped>
:deep(.el-tooltip__trigger:focus-visible) {
outline: unset;
}
</style>

19
src/main.ts Normal file
View File

@ -0,0 +1,19 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import './assets/gloable.css'
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.use(ElementPlus, {size: 'small'})
app.use(router)
app.mount('#app')

11
src/router/index.ts Normal file
View File

@ -0,0 +1,11 @@
import {createRouter, createWebHashHistory} from "vue-router";
import {routes} from "./routes";
// 创建路由实例并传递 `routes` 配置
const router = createRouter({
// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
history: createWebHashHistory(),
routes, // `routes: routes` 的缩写
})
export default router

35
src/router/routes.ts Normal file
View File

@ -0,0 +1,35 @@
export const routes = [
{
path: '/',
name:'login',
component: () => import("../views/Login.vue")
},
{
path: '/manage',
component: () => import("@/layout/Manage.vue"),
children:[
{
path: '/UserManagement',
name:'用户列表',
component: ()=> import("../views/User/UserManagement.vue")
},
{
path: '/PersonalCenter',
name:'个人中心',
component: ()=> import("../views/User/PersonalCenter.vue")
},
{
path: '/AddProduct',
name: '添加商品',
component: ()=> import("../views/Commodity/AddProduct.vue")
},
{
path: '/MerchandiseCenter',
name: '商品中心',
component: ()=> import("../views/Commodity/MerchandiseCenter.vue")
}
]
}
]

5
src/utils/emitter.ts Normal file
View File

@ -0,0 +1,5 @@
import mitt from 'mitt'
const emitter = mitt()
export default emitter

34
src/utils/request.js Normal file
View File

@ -0,0 +1,34 @@
import axios from 'axios'
const instance = axios.create({
baseURL: 'http://localhost:9090'
})
instance.interceptors.request.use(
config =>{ // 拦截器成功函数
if(config.methods == "post"){
config.data = querystring.stringify(config.data)
}
// config:包含着网络请求的所有信息
return config;
},
error =>{ // 拦截器失败函数
// 返回错误信息
return Promise.reject(error)
}
)
// 拦截器----获取数据之前
instance.interceptors.response.use(
response =>{ // 拦截器成功函数
return response.status == 200 ? Promise.resolve(response):Promise.reject(response)
},
error =>{ // 拦截器失败函数
const { response } = error;
errorHandle(response.status,response.info)
}
)
export default instance

View File

@ -0,0 +1,143 @@
<template>
<!-- 添加商品图片-->
<div style="height: auto;margin-bottom: 10px;width: 480px;">
<div style="font-size: 20px;margin-bottom: 10px">添加商品图片</div>
<el-upload action="#" v-model:file-list="uploadedFiles" list-type="picture-card" :auto-upload="false" multiple="true">
<el-icon><Plus /></el-icon>
<template #file="{ file }">
<div>
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<el-icon><zoom-in /></el-icon>
</span>
<span
v-if="!disabled"
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<el-icon><Delete /></el-icon>
</span>
</span>
</div>
</template>
</el-upload>
<!-- 添加图文描述-->
<div style="margin-bottom: 10px;">
<div style="font-size: 20px;margin-bottom: 10px">添加图文描述</div>
<el-upload action="#" v-model:file-list="uploadedDescription" list-type="picture-card" :auto-upload="false" multiple="true">
<el-icon><Plus /></el-icon>
<template #file="{ file }">
<div>
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<el-icon><zoom-in /></el-icon>
</span>
<span
v-if="!disabled"
class="el-upload-list__item-delete"
@click="descriptionRemove(file)"
>
<el-icon><Delete /></el-icon>
</span>
</span>
</div>
</template>
</el-upload>
<el-dialog v-model="dialogVisible">
<img w-full :src="dialogImageUrl" alt="Preview Image" />
</el-dialog>
</div>
<el-dialog v-model="dialogVisible">
<img w-full :src="dialogImageUrl" alt="Preview Image" />
</el-dialog>
</div>
<!-- 表单-->
<div style="position: absolute;right: 20px;top: 100px;max-width: 60%" >
<el-form :model="form" label-width="auto" style="width: 750px" size="large">
<el-form-item label="产品名称">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="产品价格">
<el-input v-model="form.price" />
</el-form-item>
<el-form-item label="产品">
<el-input v-model="form.quantity" />
</el-form-item>
<el-form-item label="是否为限定类产品" >
<el-select v-model="form.region" placeholder="否">
<el-option label="是" value="ture" />
<el-option label="否" value="false" />
</el-select>
</el-form-item>
<el-form-item v-if="form.region=='ture' " label="节日名称">
<el-input v-model="form.festivalName" />
</el-form-item>
<el-form-item label="产品类型" >
<el-radio-group v-model="form.resource" >
<el-radio value="1">材料包</el-radio>
<el-radio value="2">手持物</el-radio>
<el-radio value="3">头饰</el-radio>
<el-radio value="4">定制</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="商品标签">
<el-input v-model="form.label" type="textarea" placeholder=""/>
</el-form-item>
<el-form-item label="详情描述">
<el-input v-model="form.desc" type="textarea" placeholder="产品尺寸,服务等"/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">上架</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts" setup>
import { ref,reactive } from 'vue';
import { Delete, Plus, ZoomIn } from '@element-plus/icons-vue';
import type { UploadFile } from 'element-plus';
const dialogImageUrl = ref('');
const dialogVisible = ref(false);
const disabled = ref(false);
const uploadedFiles = ref<UploadFile[]>([]);//
const uploadedDescription = ref<UploadFile[]>([]);//
const handleRemove = (file: UploadFile) => {
uploadedFiles.value = uploadedFiles.value.filter((f) => f.uid !== file.uid);
};
const descriptionRemove = (file: UploadFile) => {
uploadedDescription.value = uploadedDescription.value.filter((f) => f.uid !== file.uid);
}
const handlePictureCardPreview = (file: UploadFile) => {
dialogImageUrl.value = file.url!;
dialogVisible.value = true;
};
const form = reactive({
name:'',
price:'',
quantity:'',//
region:'',//
festivalName:'',//
resource:'',//
label:[],//
desc:'',//
})
const onSubmit = () => {
console.log('submit!')
}
</script>

View File

@ -0,0 +1,149 @@
<template>
<div>
<div style="margin: 10px 0">
<el-input style="width: 200px; height: 30px; margin-right: 10px;" suffix-icon="Search" placeholder="请输入商品名称" v-model="username"></el-input>
<el-button class="ml-5" type="primary" @click="load" style="height: 25px;">搜索</el-button>
<el-button type="warning" @click="reset" style="height:25px">重置</el-button>
</div>
<el-table :data="tableData" border stripe header-cell-class-name="headerBg" :cell-style="{textAlign: 'center'}"
@selection-change="handleSelectionChange" :header-cell-style="{'text-align': 'center'}">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="selectedItems" label="商品编号"></el-table-column>
<el-table-column prop="uploadedFiles" label="商品图片"></el-table-column>
<el-table-column prop="name" label="商品名称" ></el-table-column>
<el-table-column prop="price" label="价格"></el-table-column>
<el-table-column prop="resource" label="类型"></el-table-column>
<el-table-column prop="quantity" label="商品数量"></el-table-column>
<el-table-column prop="state" label="状态"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="danger" slot="reference">详情<i class="el-icon-remove-outline"></i></el-button>
<el-button type="success" @click="handleEdit(scope.row)">编辑<i class="el-icon-edit"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='取消'
icon="el-icon-info"
icon-color="red"
title="您确定删除吗?"
@confirm="del(scope.row.id)"
>
<el-button type="danger" slot="reference">删除 <i class="el-icon-remove-outline"></i></el-button>
<el-button type="danger" slot="reference">下架<i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<div style="padding: 10px 0">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-size="pageSize"
:page-sizes="[2, 5, 10, 20]"
:small="null"
:disabled="null"
:background="null"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
/>
</div>
</div>
<el-dialog title="商品信息" v-model="dialogTableVisible" width="30%">
<el-table-column property="name" label="商品名称" width="150" />
<el-table-column property="price" label="商品价格" width="200" />
<el-table-column property="quantity" label="商品数量" />
<el-table-column property="region" label="是否为限定产品" />
<el-table-column property="resource" label="商品类型" />
<el-table-column property="label" label="商品标签" />
<el-table-column property="desc" label="详情描述" />
<template #footer>
<div class="dialog-footer">
<el-button style="height: 30px;" @click="dialogTableVisible = false">取消</el-button>
<el-button style="height: 30px" type="primary" @click=save>确认</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import instance from '@/utils/request';
import {ref, onMounted} from 'vue'
const tableData = ref([])
const pageNum = ref(0)
const pageSize = ref(0)
const total = ref(0)
const selectedItems = ref([])
onMounted(() => {
load()
})
const handleSelectionChange = (row: any) => {
selectedItems.value = JSON.parse(JSON.stringify(row))
}
const username = ref('')
const dialogTableVisible = ref(false)
const reset =()=>{
username.value = ''
}
const form=ref({
selectedItems:'',
uploadedFiles:'',
name:'',
price:'',
resource:'',
quantity:'',
state:'',
region:'',
label:[],
desc:'',
})
const handleEdit = (row: any) => {
dialogTableVisible.value = true
form.value = row
load()
}
const load = async () => {
await instance.get('/admin/findAllUsers').then(res => {
console.log(res.data.data)
res.data.data.foreach((item:any) => {
console.log(item)
})
tableData.value = res.data.data
})
}
const save = () => {
const formObj = toRaw(form.value)
formObj.isCarbon = formObj.isCarbon == '是' ? true : false
console.log(formObj)
instance.post('/admin/updateOrInsertUser', formObj).then(res => {
if(res.data.code == '200'){
load()
updateSuccess()
}else{
load()
updataFail()
}
})
dialogTableVisible.value = false
}
const handleAdd = async () => {
dialogTableVisible.value = true
form.value = {}
}
</script>
<style scoped>
.headerBg{
background-color: #eee !important;
}
</style>

13
src/views/Home.vue Normal file
View File

@ -0,0 +1,13 @@
<template>
<div>
<h1>这是主页</h1>
</div>
</template>
<script setup lang="ts">
</script>
<style lang="scss">
</style>

64
src/views/Login.vue Normal file
View File

@ -0,0 +1,64 @@
<template>
<div class="wrapper">
<div style="margin: 200px auto; background-color: #fff; width: 800px; height: 400px; border-radius: 10px">
<div >
<img
class="image"
style="height: 400px;width: 300px;float: left;"
src="../img/Login/login_top.png"
/>
</div>
<div style="height: 400px;width: 430px;float: left;margin:30px 0 0 40px;">
<div style="margin: 20px 0; text-align: center; font-size: 24px"><b>匠承非遗后台管理系统</b></div>
<el-form :model="user" ref="userForm">
<el-form-item prop="username">
<h2>账号</h2>
<el-input size="medium" style="margin: 10px 0" prefix-icon="el-icon-user" v-model="username"></el-input>
</el-form-item>
<el-form-item prop="password">
<h2>密码</h2>
<el-input size="medium" style="margin: 10px 0;" prefix-icon="el-icon-lock" show-password v-model="password"></el-input>
</el-form-item>
<div style="margin: 10px 0; text-align: right">
<div style="display: block;
font-size: 15px;
width: 80%;
margin: 50px auto 0 auto;
text-align: center;
border-radius: 20px;
background-color: rgb(172, 115, 82);
line-height: 40px;
" @click="login">登录</div>
</div>
</el-form>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {ref, reactive} from 'vue'
import { ElMessage } from 'element-plus'
import {useRouter} from 'vue-router'
const user = ref({})
const username = ref('')
const password = ref('')
const router = useRouter()
const login = () => {
// console.log(username)
// console.log(password)
if(username.value ==="a"&& password.value ==="1"){
router.push("/UserManagement")
}}
</script>
<style scoped>
.wrapper{
height: 100vh;
background-image:url("../img/Login/登录底图.png");
background-size: 100% 100%;
background-repeat: no-repeat;
overflow: hidden;
}
</style>

32
src/views/Person.vue Normal file
View File

@ -0,0 +1,32 @@
<template>
<el-card style="width: 500px">
<el-form label-width="80px" size="small">
<el-form-item label="用户名">
<el-input v-model="form.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="学号">
<el-input v-model="form.nickname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.email" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="电话">
<el-input v-model="form.phone" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="地址">
<el-input v-model="form.address" autocomplete="off"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="save"> </el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script>
</script>
<style scoped>
</style>

View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
个人中心
</template>
<style scoped>
</style>

View File

@ -0,0 +1,104 @@
<template>
<div>
<div style="margin: 10px 0">
<el-input style="width: 200px; height: 30px; margin-right: 10px;" suffix-icon="Search" placeholder="请输入用户名" v-model="username"></el-input>
<el-button class="ml-5" type="primary" @click="load" style="height: 25px;">搜索</el-button>
<el-button type="warning" @click="reset" style="height:25px">重置</el-button>
</div>
<!-- <div style="margin: 15px 0">-->
<!-- <el-button class="ml-5" type="primary" @click="handleAdd" style="height: 25px;">新增 <el-icon style="margin-left: 5px"><CirclePlus /></el-icon></el-button>-->
<!-- <el-popconfirm-->
<!-- class="ml-5"-->
<!-- confirm-button-text='确定'-->
<!-- cancel-button-text='取消'-->
<!-- icon="InfoFilled"-->
<!-- icon-color="red"-->
<!-- title="您确定批量删除这些数据吗?"-->
<!-- @confirm="delBatch"-->
<!-- width=180-->
<!-- >-->
<!-- <template #reference>-->
<!-- <el-button style="height: 25px" class="ml-5" type="danger" slot="reference">批量删除 <el-icon style="margin-left: 5px;"><Remove /></el-icon></el-button>-->
<!-- </template>-->
<!-- </el-popconfirm>-->
<!-- </div>-->
<el-table :data="tableData" border stripe header-cell-class-name="headerBg" :cell-style="{textAlign: 'center'}"
@selection-change="handleSelectionChange" :header-cell-style="{'text-align': 'center'}">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="序号" width="50"></el-table-column>
<el-table-column prop="username" label="用户昵称" ></el-table-column>
<el-table-column prop="avatar" label="头像"></el-table-column>
<el-table-column prop="identity" label="身份"></el-table-column>
<el-table-column prop="phone" label="手机号"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="success" @click="handleEdit(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='取消'
icon="el-icon-info"
icon-color="red"
title="您确定删除吗?"
@confirm="del(scope.row.id)"
>
<el-button type="danger" slot="reference">删除 <i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<div style="padding: 10px 0">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-size="pageSize"
:page-sizes="[2, 5, 10, 20]"
:small="null"
:disabled="null"
:background="null"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
/>
</div>
</div>
</template>
<script setup lang="ts">
import instance from '@/utils/request';
import {ref, onMounted} from 'vue'
const tableData = ref([])
const pageNum = ref(0)
const pageSize = ref(0)
const total = ref(0)
onMounted(() => {
load()
})
const username = ref('')
const reset =()=>{
username.value = ''
}
const load = async () => {
await instance.get('/admin/findAllUsers').then(res => {
console.log(res.data.data)
res.data.data.foreach((item:any) => {
console.log(item)
})
tableData.value = res.data.data
})
}
</script>
<style scoped>
.headerBg{
background-color: #eee !important;
}
</style>

14
tsconfig.app.json Normal file
View File

@ -0,0 +1,14 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"allowJs": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}

11
tsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

18
tsconfig.node.json Normal file
View File

@ -0,0 +1,18 @@
{
"extends": "@tsconfig/node20/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"composite": true,
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

16
vite.config.ts Normal file
View File

@ -0,0 +1,16 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})