初始化

This commit is contained in:
YuNan 2025-02-17 23:06:19 +08:00
commit 8a19c93d22
21 changed files with 23388 additions and 0 deletions

5
.editorconfig Normal file
View File

@ -0,0 +1,5 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

23
.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

24
README.md Normal file
View File

@ -0,0 +1,24 @@
# ecs_vue
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

5
babel.config.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

19
jsconfig.json Normal file
View File

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

22322
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

51
package.json Normal file
View File

@ -0,0 +1,51 @@
{
"name": "ecs_vue",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.8.3",
"vue": "^3.2.13",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"@vue/eslint-config-standard": "^6.1.0",
"eslint": "^7.32.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-vue": "^8.0.3"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/vue3-essential",
"@vue/standard"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead",
"not ie 11"
]
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

17
public/index.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

26
src/App.vue Normal file
View File

@ -0,0 +1,26 @@
<template>
<router-view/>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
nav {
padding: 30px;
}
nav a {
font-weight: bold;
color: #2c3e50;
}
nav a.router-link-exact-active {
color: #42b983;
}
</style>

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

6
src/main.js Normal file
View File

@ -0,0 +1,6 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App).use(store).use(router).mount('#app')

56
src/router/index.js Normal file
View File

@ -0,0 +1,56 @@
import { createRouter, createWebHistory } from 'vue-router'
import Login from '../views/auth/Login.vue'
import Register from '../views/auth/Register.vue'
import AdminDashboard from '../views/admin/AdminDashboard.vue'
import StaffDashboard from '../views/staff/StaffDashboard.vue'
import CustomerDashboard from '../views/customer/CustomerDashboard.vue'
import CustomerHome from '../views/customer/CustomerHome.vue'
const routes = [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/register',
name: 'Register',
component: Register
},
{
path: '/admin',
name: 'AdminDashboard',
component: AdminDashboard,
meta: { requiresAuth: true, role: 'admin' }
},
{
path: '/staff',
name: 'StaffDashboard',
component: StaffDashboard,
meta: { requiresAuth: true, role: 'staff' }
},
{
path: '/customer',
name: 'CustomerDashboard',
component: CustomerDashboard,
meta: { requiresAuth: true, role: 'customer' },
children: [
{
path: '',
name: 'CustomerHome',
component: CustomerHome
}
]
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router

14
src/store/index.js Normal file
View File

@ -0,0 +1,14 @@
import { createStore } from 'vuex'
export default createStore({
state: {
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
})

View File

@ -0,0 +1,143 @@
<template>
<div class="admin-dashboard">
<header class="dashboard-header">
<h1>管理员控制台</h1>
<button @click="logout">退出登录</button>
</header>
<div class="dashboard-content">
<nav class="sidebar">
<ul>
<li @click="currentView = 'staff'">员工管理</li>
<li @click="currentView = 'customers'">顾客管理</li>
<li @click="currentView = 'services'">服务管理</li>
<li @click="currentView = 'reports'">统计报表</li>
</ul>
</nav>
<main class="main-content">
<!-- 员工管理 -->
<div v-if="currentView === 'staff'" class="staff-management">
<h2>员工管理</h2>
<table>
<thead>
<tr>
<th>员工ID</th>
<th>姓名</th>
<th>职位</th>
<th>联系方式</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="staff in staffList" :key="staff.id">
<td>{{ staff.id }}</td>
<td>{{ staff.name }}</td>
<td>{{ staff.position }}</td>
<td>{{ staff.contact }}</td>
<td>
<button @click="editStaff(staff)">编辑</button>
<button @click="deleteStaff(staff.id)">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 其他视图可以根据需要添加 -->
</main>
</div>
</div>
</template>
<script>
export default {
name: 'AdminDashboard',
data () {
return {
currentView: 'staff',
staffList: [
{ id: 1, name: '张三', position: '护工', contact: '13800138000' },
{ id: 2, name: '李四', position: '护士', contact: '13800138001' }
]
}
},
methods: {
logout () {
// 退
this.$router.push('/login')
},
editStaff (staff) {
//
console.log('编辑员工:', staff)
},
deleteStaff (staffId) {
//
console.log('删除员工:', staffId)
}
}
}
</script>
<style scoped>
.admin-dashboard {
height: 100vh;
display: flex;
flex-direction: column;
}
.dashboard-header {
background: #2c3e50;
color: white;
padding: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.dashboard-content {
display: flex;
flex: 1;
}
.sidebar {
width: 200px;
background: #34495e;
color: white;
padding: 1rem;
}
.sidebar ul {
list-style: none;
padding: 0;
}
.sidebar li {
padding: 10px;
cursor: pointer;
}
.sidebar li:hover {
background: #2c3e50;
}
.main-content {
flex: 1;
padding: 1rem;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
</style>

102
src/views/auth/Login.vue Normal file
View File

@ -0,0 +1,102 @@
<template>
<div class="login-container">
<div class="login-box">
<h2>登录系统</h2>
<form @submit.prevent="handleLogin">
<div class="form-group">
<label>用户名</label>
<input type="text" v-model="username" required>
</div>
<div class="form-group">
<label>密码</label>
<input type="password" v-model="password" required>
</div>
<div class="form-group">
<label>用户类型</label>
<select v-model="userType">
<option value="admin">管理员</option>
<option value="staff">员工</option>
<option value="customer">顾客</option>
</select>
</div>
<button type="submit">登录</button>
</form>
<!-- 添加注册链接 -->
<div class="form-footer">
<p>还没有账号<router-link to="/register">立即注册</router-link></p>
</div>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Login',
data () {
return {
username: '',
password: '',
userType: 'customer'
}
},
methods: {
handleLogin () {
//
console.log('登录信息:', this.username, this.password, this.userType)
}
}
}
</script>
<style scoped>
.login-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f5f5;
}
.login-box {
width: 400px;
padding: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.form-group {
margin-bottom: 15px;
}
input, select {
width: 100%;
padding: 8px;
margin-top: 5px;
}
button {
width: 100%;
padding: 10px;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.form-footer {
margin-top: 15px;
text-align: center;
}
.form-footer a {
color: #4CAF50;
text-decoration: none;
}
.form-footer a:hover {
text-decoration: underline;
}
</style>

110
src/views/auth/Register.vue Normal file
View File

@ -0,0 +1,110 @@
<template>
<div class="register-container">
<div class="register-box">
<h2>注册账号</h2>
<form @submit.prevent="handleRegister">
<div class="form-group">
<label>用户名</label>
<input type="text" v-model="username" required>
</div>
<div class="form-group">
<label>密码</label>
<input type="password" v-model="password" required>
</div>
<div class="form-group">
<label>确认密码</label>
<input type="password" v-model="confirmPassword" required>
</div>
<div class="form-group">
<label>用户类型</label>
<select v-model="userType">
<option value="customer">顾客</option>
<option value="staff">员工</option>
</select>
</div>
<button type="submit">注册</button>
</form>
<!-- 添加登录链接 -->
<div class="form-footer">
<p>已有账号<router-link to="/login">立即登录</router-link></p>
</div>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Register',
data () {
return {
username: '',
password: '',
confirmPassword: '',
userType: 'customer'
}
},
methods: {
handleRegister () {
if (this.password !== this.confirmPassword) {
alert('两次输入的密码不一致!')
return
}
//
console.log('注册信息:', this.username, this.password, this.userType)
}
}
}
</script>
<style scoped>
.register-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f5f5;
}
.register-box {
width: 400px;
padding: 20px;
background: white;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.form-group {
margin-bottom: 15px;
}
input, select {
width: 100%;
padding: 8px;
margin-top: 5px;
}
button {
width: 100%;
padding: 10px;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.form-footer {
margin-top: 15px;
text-align: center;
}
.form-footer a {
color: #4CAF50;
text-decoration: none;
}
.form-footer a:hover {
text-decoration: underline;
}
</style>

View File

@ -0,0 +1,80 @@
<template>
<div class="customer-dashboard">
<header class="dashboard-header">
<h1>顾客服务中心</h1>
<nav class="main-nav">
<router-link to="/customer" class="nav-link">首页</router-link>
<router-link to="/customer/services" class="nav-link">服务预约</router-link>
<router-link to="/customer/schedule" class="nav-link">我的日程</router-link>
<router-link to="/customer/profile" class="nav-link">个人信息</router-link>
</nav>
<button @click="logout">退出登录</button>
</header>
<div class="dashboard-content">
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'CustomerDashboard',
methods: {
logout () {
this.$router.push('/login')
}
}
}
</script>
<style scoped>
.customer-dashboard {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.dashboard-header {
background: #2c3e50;
color: white;
padding: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.main-nav {
display: flex;
gap: 20px;
}
.nav-link {
color: white;
text-decoration: none;
padding: 5px 10px;
border-radius: 4px;
}
.nav-link:hover,
.nav-link.router-link-active {
background: rgba(255,255,255,0.1);
}
.dashboard-content {
flex: 1;
}
button {
background: #4CAF50;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #45a049;
}
</style>

View File

@ -0,0 +1,237 @@
<template>
<div class="customer-home">
<!-- 轮播图部分 -->
<div class="carousel">
<div class="carousel-container" :style="{ transform: `translateX(-${currentIndex * 100}%)` }">
<div v-for="(slide, index) in slides" :key="index" class="carousel-slide">
<img :src="slide.image" :alt="slide.title">
<div class="slide-content">
<h2>{{ slide.title }}</h2>
<p>{{ slide.description }}</p>
</div>
</div>
</div>
<div class="carousel-dots">
<span
v-for="(slide, index) in slides"
:key="index"
:class="{ active: currentIndex === index }"
@click="setSlide(index)"
></span>
</div>
</div>
<!-- 系统介绍部分 -->
<div class="system-intro">
<h1>养老服务系统</h1>
<div class="intro-cards">
<div class="intro-card">
<i class="fas fa-heart"></i>
<h3>专业照护</h3>
<p>提供24小时专业护理服务确保老年人得到细致周到的照顾</p>
</div>
<div class="intro-card">
<i class="fas fa-user-md"></i>
<h3>医疗保障</h3>
<p>配备专业医疗团队定期体检及时响应健康需求</p>
</div>
<div class="intro-card">
<i class="fas fa-hands-helping"></i>
<h3>生活照料</h3>
<p>提供饮食起居清洁卫生等全方位生活服务</p>
</div>
</div>
</div>
<!-- 服务特色部分 -->
<div class="service-features">
<h2>我们的服务特色</h2>
<div class="features-grid">
<div class="feature">
<h3>个性化服务</h3>
<p>根据每位老人的具体需求制定个性化的护理方案</p>
</div>
<div class="feature">
<h3>智能监护</h3>
<p>采用现代化设备实时监测老人的身体状况</p>
</div>
<div class="feature">
<h3>营养配餐</h3>
<p>专业营养师搭配确保营养均衡</p>
</div>
<div class="feature">
<h3>文娱活动</h3>
<p>丰富多样的文化娱乐活动丰富晚年生活</p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'CustomerHome',
data () {
return {
currentIndex: 0,
slides: [
{
image: '/images/slide1.jpg', //
title: '温馨舒适的生活环境',
description: '为老年人提供宾至如归的居住体验'
},
{
image: '/images/slide2.jpg',
title: '专业的医疗护理团队',
description: '24小时专业护理保障老年人健康'
},
{
image: '/images/slide3.jpg',
title: '丰富多彩的文娱活动',
description: '让晚年生活充满欢乐与活力'
}
]
}
},
methods: {
setSlide (index) {
this.currentIndex = index
}
},
mounted () {
//
setInterval(() => {
this.currentIndex = (this.currentIndex + 1) % this.slides.length
}, 5000)
}
}
</script>
<style scoped>
.customer-home {
width: 100%;
}
/* 轮播图样式 */
.carousel {
position: relative;
width: 100%;
height: 500px;
overflow: hidden;
}
.carousel-container {
display: flex;
transition: transform 0.5s ease-in-out;
height: 100%;
}
.carousel-slide {
min-width: 100%;
position: relative;
}
.carousel-slide img {
width: 100%;
height: 100%;
object-fit: cover;
}
.slide-content {
position: absolute;
bottom: 50px;
left: 50px;
color: white;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
.carousel-dots {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
}
.carousel-dots span {
width: 12px;
height: 12px;
border-radius: 50%;
background: rgba(255,255,255,0.5);
cursor: pointer;
}
.carousel-dots span.active {
background: white;
}
/* 系统介绍样式 */
.system-intro {
padding: 50px 20px;
text-align: center;
}
.intro-cards {
display: flex;
justify-content: center;
gap: 30px;
margin-top: 40px;
}
.intro-card {
flex: 1;
max-width: 300px;
padding: 30px;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
transition: transform 0.3s;
}
.intro-card:hover {
transform: translateY(-5px);
}
.intro-card i {
font-size: 40px;
color: #4CAF50;
margin-bottom: 20px;
}
/* 服务特色样式 */
.service-features {
background: #f5f5f5;
padding: 50px 20px;
text-align: center;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 30px;
margin-top: 40px;
padding: 0 50px;
}
.feature {
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
h1, h2 {
color: #2c3e50;
margin-bottom: 20px;
}
h3 {
color: #34495e;
margin-bottom: 15px;
}
p {
color: #666;
line-height: 1.6;
}
</style>

View File

@ -0,0 +1,144 @@
<template>
<div class="staff-dashboard">
<header class="dashboard-header">
<h1>员工工作台</h1>
<button @click="logout">退出登录</button>
</header>
<div class="dashboard-content">
<nav class="sidebar">
<ul>
<li @click="currentView = 'tasks'">工作任务</li>
<li @click="currentView = 'schedule'">排班表</li>
<li @click="currentView = 'customers'">顾客信息</li>
</ul>
</nav>
<main class="main-content">
<!-- 工作任务视图 -->
<div v-if="currentView === 'tasks'" class="tasks-view">
<h2>今日工作任务</h2>
<div class="task-list">
<div v-for="task in tasks" :key="task.id" class="task-card">
<h3>{{ task.title }}</h3>
<p>顾客{{ task.customer }}</p>
<p>时间{{ task.time }}</p>
<p>状态{{ task.status }}</p>
<button @click="completeTask(task.id)">完成任务</button>
</div>
</div>
</div>
</main>
</div>
</div>
</template>
<script>
export default {
name: 'StaffDashboard',
data () {
return {
currentView: 'tasks',
tasks: [
{
id: 1,
title: '晨间护理',
customer: '王老先生',
time: '08:00-09:00',
status: '待完成'
},
{
id: 2,
title: '用药提醒',
customer: '李奶奶',
time: '09:30-10:00',
status: '待完成'
}
]
}
},
methods: {
logout () {
this.$router.push('/login')
},
completeTask (taskId) {
//
console.log('完成任务:', taskId)
}
}
}
</script>
<style scoped>
.staff-dashboard {
height: 100vh;
display: flex;
flex-direction: column;
}
.dashboard-header {
background: #2c3e50;
color: white;
padding: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.dashboard-content {
display: flex;
flex: 1;
}
.sidebar {
width: 200px;
background: #34495e;
color: white;
padding: 1rem;
}
.sidebar ul {
list-style: none;
padding: 0;
}
.sidebar li {
padding: 10px;
cursor: pointer;
}
.sidebar li:hover {
background: #2c3e50;
}
.main-content {
flex: 1;
padding: 1rem;
}
.task-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
}
.task-card {
background: white;
padding: 1rem;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
button {
background: #4CAF50;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #45a049;
}
</style>

4
vue.config.js Normal file
View File

@ -0,0 +1,4 @@
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true
})