Compare commits

..

113 Commits
master ... dev

Author SHA1 Message Date
sundongyu
243ce97421 🐞 fix:紧急修复了滚动条 2024-04-16 16:18:01 +08:00
sundongyu
ff926d6f91 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-16 16:12:42 +08:00
sundongyu
839c0ed6e1 🐞 fix:修复了菜单滚动条 2024-04-16 16:12:38 +08:00
ycy
c50457f8ee feat: 增加页面拖动效果 2024-04-16 16:09:13 +08:00
sundongyu
72384dc7ba Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-16 13:33:35 +08:00
sundongyu
e5190eac63 🐞 fix: 2024-04-16 13:33:28 +08:00
ycy
f6c573c69e 🦄 refactor: 将所有表单弹出框写成一个文件,将用到的下拉款写成一个文件,将插槽写到src代码里 2024-04-15 18:04:02 +08:00
ycy
5f82bbf7c9 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-15 09:18:28 +08:00
sundongyu
bd4f531645 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-14 15:03:24 +08:00
sundongyu
f1ee4efbd0 feat:完成了学生信息统计功能等页面 2024-04-14 15:03:20 +08:00
ycy
a28eff4ab6 🐞 fix: 修改票据领用点击父节点右侧列表变化的问题 2024-04-11 18:04:16 +08:00
ycy
2bf79cc724 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-11 16:38:43 +08:00
ycy
f7171e1564 🦄 refactor: 更改查询框的样式 2024-04-11 16:38:38 +08:00
sundongyu
b647880ea6 🐎 ci:配置了prettier 2024-04-11 16:19:02 +08:00
sundongyu
e9aed32e8b Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-11 16:08:13 +08:00
sundongyu
f040923136 feat:添加了部门交费分析表 2024-04-11 16:08:08 +08:00
ycy
3a3e268f69 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-11 11:42:17 +08:00
ycy
a1fa3a29d9 🐞 fix: 修改票据领用需要刷新两次页面才会出现数据的bug 2024-04-11 11:42:12 +08:00
吕才卓
087756c014 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-10 18:03:02 +08:00
吕才卓
4c530bf7f8 stu 2024-04-10 18:02:53 +08:00
ycy
0d0c7de975 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-10 15:07:30 +08:00
ycy
f53d392a6c feat: 导出pdf 2024-04-10 15:06:54 +08:00
sundongyu
3a0821334d feat:开会前的提交 2024-04-10 13:21:33 +08:00
sundongyu
923bebedf1 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-10 11:46:46 +08:00
sundongyu
a5c42f3bc3 🐞 fix:修复了助学贷款的搜索页面 2024-04-10 11:46:41 +08:00
吕才卓
3730730f1e stu 2024-04-10 09:14:35 +08:00
sundongyu
4c9667e84b Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-09 19:00:22 +08:00
sundongyu
766435b4d8 feat:完成了日常报表 2024-04-09 19:00:18 +08:00
吕才卓
74cebfe7d4 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-09 18:05:48 +08:00
吕才卓
a2b2a66c31 stu 2024-04-09 18:05:19 +08:00
吕才卓
fba8df4041 stu 2024-04-09 17:35:48 +08:00
ycy
ae216140dc feat: 增加导出excel按钮 2024-04-09 17:18:01 +08:00
ycy
9ebafccc2f Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-09 16:44:23 +08:00
ycy
5381a970e6 🌈 style: 增加注释 2024-04-09 16:42:45 +08:00
ycy
abac43466f feat: 首页代码完成 封装echart组件 2024-04-09 16:40:21 +08:00
sundongyu
9953d500e3 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-09 16:40:11 +08:00
sundongyu
13fd2c21fd feat:完成了减免费用表 2024-04-09 16:40:06 +08:00
ycy
72beb9cff4 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-09 13:34:54 +08:00
ycy
f71bc80566 feat: 报表明细页面完成 2024-04-09 13:34:49 +08:00
sundongyu
5651aed6b7 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-09 13:08:07 +08:00
sundongyu
44a85343a5 feat:添加了图表表可以通过多个维度切换 2024-04-09 13:08:04 +08:00
ycy
1bbb64d837 feat:票据核销页面完成 2024-04-09 10:48:03 +08:00
ycy
610ba20dab 🦄 refactor: 2024-04-09 10:05:42 +08:00
ycy
9041591d98 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-09 09:50:43 +08:00
ycy
dc27f047f3 🦄 refactor: 票据审核页面代码重构 2024-04-09 09:50:38 +08:00
sundongyu
53dc363736 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-08 20:08:27 +08:00
sundongyu
b57abb9ab7 feat:完成了贷款页面 2024-04-08 20:08:23 +08:00
吕才卓
837e570061 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-08 18:14:01 +08:00
吕才卓
fecbc1d096 stu 2024-04-08 18:13:54 +08:00
ycy
7407d6afa2 feat: 票据核销页面未完成 2024-04-08 18:03:48 +08:00
ycy
61e34db972 feat: 票据报损管理页面完成 2024-04-08 16:29:46 +08:00
ycy
8b58ff2c70 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-08 14:08:54 +08:00
ycy
c03aed34df feat: 票据退领管理 2024-04-08 14:08:50 +08:00
ycy
61ea10ecf3 🦄 refactor: 更改左侧菜单排序 2024-04-08 13:01:52 +08:00
sundongyu
735135a86b Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-08 13:01:36 +08:00
sundongyu
b55b8d6ede 🦄 refactor:修改-连接 2024-04-08 13:01:00 +08:00
ycy
63ffd54948 增加学生管理路由 2024-04-08 12:56:45 +08:00
吕才卓
ad899d0238 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-08 12:40:37 +08:00
ycy
ee31fe4dc4 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-08 12:02:05 +08:00
ycy
ec8e9d314c 🦄 refactor: 票据领用代码重构 2024-04-08 12:02:00 +08:00
吕才卓
10a46e041c feat:学生页面 2024-04-08 12:00:15 +08:00
sundongyu
20636b6c84 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-08 11:57:14 +08:00
sundongyu
4947b7e1ec feat:完成了可以添加学生收费金额的管理 2024-04-08 11:57:10 +08:00
ycy
ea61580c55 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-08 10:37:51 +08:00
ycy
dfc4cf59e3 feat: 票据领用管理页面完成 2024-04-08 10:37:44 +08:00
吕才卓
050e0bc6d3 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-08 09:14:41 +08:00
sundongyu
220d9d4fd8 feat:添加了发票 2024-04-07 22:15:44 +08:00
sundongyu
2ef3ac7697 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-07 21:41:14 +08:00
sundongyu
dfdfbd2c5a feat:完成应收管理的学生费用 2024-04-07 21:41:06 +08:00
吕才卓
fbbf731322 password 2024-04-07 18:09:58 +08:00
ycy
ec58a2a81c feat: 票据领用管理页面布局完成,左侧树状图完成(还没有加点击事件) 2024-04-07 18:02:23 +08:00
吕才卓
a25572301d password 2024-04-07 17:36:32 +08:00
ycy
e0ea35c789 🐞 fix: css格式scss修改为less 2024-04-07 16:04:53 +08:00
ycy
74ceb12353 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-07 16:03:31 +08:00
ycy
dcf662b4f4 feat: 票据退库管理页面完成 2024-04-07 16:03:27 +08:00
吕才卓
351232b4be Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-07 15:18:40 +08:00
吕才卓
4856f437b5 password 2024-04-07 15:17:13 +08:00
ycy
68e6e55810 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-07 10:24:12 +08:00
ycy
20d3c2b9ad feat: 完成票据入库管理 2024-04-07 10:17:43 +08:00
sundongyu
d931037347 🐞 fix:修复了应收款管理的查询学号失败的问题 2024-04-07 09:54:43 +08:00
sundongyu
0176354677 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 19:00:34 +08:00
sundongyu
51cabf8107 feat:完成了应收款管理页面显示 2024-04-06 19:00:30 +08:00
ycy
9aa7386b7e Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 18:21:02 +08:00
ycy
b0706b2ee5 feat: 票据入库管理页面列表完成,查询完成,新增完成 2024-04-06 18:20:58 +08:00
吕才卓
448c0b0e1f Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 18:08:11 +08:00
吕才卓
f4a26c5b69 登陆 2024-04-06 18:02:03 +08:00
sundongyu
855f64b21c 🐞 fix:解决mock问题 2024-04-06 15:44:32 +08:00
sundongyu
12f2274971 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 15:30:04 +08:00
ycy
532f8c73a8 feat: mock接口上传 2024-04-06 15:29:30 +08:00
sundongyu
ac1d8b0862 feat:生成了mock数据 2024-04-06 15:27:58 +08:00
吕才卓
4af1a40d96 login 2024-04-06 15:25:22 +08:00
吕才卓
46d05fc7aa Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 15:24:21 +08:00
吕才卓
5f2bb4c9a8 stu 2024-04-06 15:15:18 +08:00
ycy
b62b4272f1 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 15:10:22 +08:00
ycy
616c21a62d feat: axiox二次封装配置代理解决跨域 2024-04-06 15:09:43 +08:00
sundongyu
6721db0002 feat:初步完成了应收页面 2024-04-06 15:06:22 +08:00
sundongyu
8bb6b10f02 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 14:18:34 +08:00
ycy
47929faa04 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 14:18:21 +08:00
ycy
a949bff448 feat: 票据入库管理页面完成 2024-04-06 14:17:49 +08:00
sundongyu
5213fce8ff feat:初步完成了应收页面 2024-04-06 14:17:20 +08:00
吕才卓
cc69ee0489 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 13:25:30 +08:00
吕才卓
2dd7937e77 登陆 2024-04-06 13:25:05 +08:00
sundongyu
5b66b7a60f Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 11:36:38 +08:00
sundongyu
32bbe5daf9 feat:创建了应收款管理菜单 2024-04-06 11:36:32 +08:00
吕才卓
c888946994 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 11:30:30 +08:00
吕才卓
ca049de3c8 登陆 2024-04-06 11:28:15 +08:00
sundongyu
550a598d45 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 11:27:58 +08:00
sundongyu
e170e391e7 feat:创建了路由重定向 2024-04-06 11:27:04 +08:00
ycy
923a9ae1ed feat: layout配置二级菜单 2024-04-06 11:25:56 +08:00
ycy
f0fc0ae310 Merge branch 'dev' of https://gitea.dykj.co/sundongyu/dykj-college-back-office-management-system into dev 2024-04-06 11:12:39 +08:00
ycy
42318ebaca feat: 票据管理票据入库路由上传 2024-04-06 11:10:22 +08:00
sundongyu
1d84332a35 feat:完成layout布局 2024-04-06 11:04:48 +08:00
ycy
5b640ce26e 🎉 init: 上传公共样式,下载依赖包 2024-04-06 09:55:10 +08:00
83 changed files with 13433 additions and 918 deletions

View File

@ -0,0 +1,6 @@
import sdy from './modules/sdy'
import ycy from './modules/ycy'
export default [
...sdy,
...ycy
]

99
mock/modules/lcz.js Normal file
View File

@ -0,0 +1,99 @@
import Mock from "mockjs"
const student = Mock.mock({
"list|100": [
{
"Id|+1": 1,
"name": "@cname",
"gender": `@pick(['男', '女'])`,
"studentId": "@integer(1000000000,9999999999)",
"department": `@pick(['机电工程系', '护理分院','建筑系','材料科学与工程系','环境科学与工程系'])`,
"major": `@pick(['机械制造与自动化', '材料科学与工程', '环境科学与工程', '建筑工程', '护理学'])`,
"classes": `@pick(['机制1班', '材料1班', '环境1班', '建筑1班','护理1班'])`,
"status": `@pick(['休学', '退学', '复学'])`,
},
],
});
export default [
{
url: '/api-list',
method: 'get',
response: () => {
return {
code: 200,
data: student
}
}
},
{
url: '/api-updateStudent',
method: 'post',
response(req) {
// 假设req.body的结构是{Id: '唯一标识', ...其他字段}
const requestBody = req.body;
const studentId = requestBody.Id;
// 模拟检查数据库中是否存在该id
// 在真实环境中,这一步应当由后端服务完成
const students = getMockStudents(); // 假设这是存储模拟学生数据的地方
const existingStudent = students.find(student => student.id === studentId);
if (existingStudent) {
// 更新数据库中的学生信息(在模拟中,我们直接修改内存中的数据)
Object.assign(existingStudent, requestBody);
return {
code: 200,
message: '更新成功',
data: existingStudent
};
} else {
return {
code: 404,
message: '未找到具有该ID的学生'
};
}
}
},
{
url: '/api-student',
method: 'post',
response: (req) => {
if (req.body.name !== '') {
return student.list.filter(item => item.name.includes(req.body.name))
}
else if (req.body.studentId !== '') {
const studentId = Number(req.body.studentId)
if (!isNaN(studentId)) {
return student.list.filter(item => item.studentId === studentId)
} else {
return {
code: 400,
message: 'Invalid student number format'
}
}
}
else if (req.body.name !== '') {
return student.list.filter(item => item.name.includes(req.body.name))
}
else if (req.body.gender !== '') {
return student.list.filter(item => item.gender.includes(req.body.gender))
}
else if (req.body.department !== '') {
return student.list.filter(item => item.grade.includes(req.body.department))
}
else if (req.body.major !== '') {
return student.list.filter(item => item.major.includes(req.body.major))
}
else if (req.body.classes !== '') {
return student.list.filter(item => item.classes.includes(req.body.classes))
}
else if (req.body.status !== '') {
return student.list.filter(item => item.major.includes(req.body.status))
}
return {
code: 200,
}
}
}
]

618
mock/modules/sdy.js Normal file
View File

@ -0,0 +1,618 @@
import Mock from "mockjs"
const data = Mock.mock({
"list|200": [
{
"id|+1": '1',
"name": "@cname",
"studentnumber": "@integer(1000000000,9999999999)",
"department": `@pick(['机电工程系', '护理分院','建筑系','材料科学与工程系','环境科学与工程系'])`,
"major": `@pick(['机械制造与自动化', '材料科学与工程', '环境科学与工程', '建筑工程', '护理学'])`,
"grade": `@pick(['机制1班', '材料1班', '环境1班', '建筑1班','护理1班'])`,
"tuition": `@pick(['已付学费', '未缴学费'])`,
"tu": 16800,
}
]
})
const loans = Mock.mock({
"list|45": [
{
"id|+1": 1,
'proposer': '@cname',
'student': '@integer(100000000,999999999)',
'allowance': '@integer(10000,50000)',
'department': '@pick(["机电工程系","护理分院","建筑系","材料科学与工程系","环境科学与工程系"])',
'cation': '@pick(["2021-2022学年度","2022-2023学年度"])',
'loanTerm': '@pick(["已放款","未放款"])',
'timeofapplication': "@now('yyyy-MM-dd')",
}
]
})
const daily = Mock.mock({
'list|10': [
{
'date': "@now('yyyy-MM-dd')",
'tuiti': '@integer(10000,50000)',
'incidentals': '@integer(1000,5000)',
'materials': '@integer(1000,5000)',
'major': '@integer(1000,5000)',
'grade': '@integer(1000,5000)',
'tuit': '@integer(10000,50000)',
'cost': '@integer(10000,50000)',
'tuition': '@integer(10000,50000)',
}
]
})
const paragraph = Mock.mock({
'list|15': [
{
'name': '@cname',
department: '机电工程系',
grade: '机制1班',
counselor: '王刚',
cellPhone: '13354679999',
money: 16800,
condition: '未还款'
},
{
'name': '@cname',
department: '护理分院',
grade: '护理1班',
counselor: '李昆',
cellPhone: '18845065230',
money: 24000,
condition: '未还款'
},
{
'name': '@cname',
department: '建筑系',
grade: '建筑1班',
counselor: '张明',
cellPhone: '16656664666',
money: 12000,
condition: '未还款'
}
]
})
const analysis = Mock.mock({
list: [
{
id: 1,
name: '机电工程系',
studentnumber: 120,
department: 120,
major: 80,
grade: '1344000',
tuition: 40,
weigrade: 672000,
shition: 2016000
},
{
id: 2,
name: '护理分院',
studentnumber: 200,
department: 200,
major: 120,
grade: '2016000',
tuition: 80,
weigrade: 1344000,
shition: 33600000
},
{
id: 3,
name: '建筑系',
studentnumber: 300,
department: 300,
major: 200,
grade: '2016000',
tuition: 100,
weigrade: 1680000,
shition: 5040000
}
]
})
const message = Mock.mock({
'list|10': [
{
'id|+1': 1,
//学生姓名
'name': '@cname',
//学生学号
'studentNumber': '@integer(132000000,1329999999)',
//性别
'gender': '@pick(["男","女"])',
//年龄
'age': '@integer(20,21)',
//学院
'date': '@date',
//籍贯
'nativePlace': "@city",
//民族
'nation': '汉族',
//入学时间
'enrollmentyear': '@now("yyyy")',
//部门
'college': '机电工程系',
//专业
'major': '机械制造与自动化',
//部门
'grade': '机制1班',
//辅导员
'tutor': '王刚',
//手机号
'phone': '@integer(13200000000,13299999999)',
},
{
'id|+1': 11,
//学生姓名
'name': '@cname',
//学生学号
'studentNumber': '@integer(188000000,18899999999)',
//性别
'gender': '@pick(["男","女"])',
//年龄
'age': '@integer(20,21)',
//学院
'date': '@date',
//籍贯
'nativePlace': "@city",
//民族
'nation': '汉族',
//入学时间
'enrollmentyear': '@now("yyyy")',
//部门
'college': '护理分院',
//专业
'major': '护理学',
//部门
'grade': '护理学1班',
//辅导员
'tutor': '张明',
//手机号
'phone': '@integer(18800000000,18899999999)',
},
{
'id|+1': 21,
//学生姓名
'name': '@cname',
//学生学号
'studentNumber': '@integer(186000000,1869999999)',
//性别
'gender': '@pick(["男","女"])',
//年龄
'age': '@integer(20,21)',
//出生时间
'date': '@date',
//籍贯
'nativePlace': "@city",
//民族
'nation': '汉族',
//入学时间
'enrollmentyear': '@now("yyyy")',
//部门
'college': '建筑系',
//专业
'major': '建筑工程',
//部门
'grade': '建筑1班',
//辅导员
'tutor': '李宇',
//手机号
'phone': '@integer(18600000000,18699999999)',
}
]
})
const mitigate = Mock.mock({
'list|10': [
{
'id|+1': 1,
//学生姓名
'name': '@cname',
//学生学号
'studentNumber': '@integer(132000000,1329999999)',
//性别
'gender': '@pick(["男","女"])',
//年龄
'age': '@integer(20,21)',
//学费
'tuition': 16800,
//减免金额
'mitigate': 12800,
//入学时间
'enrollmentyear': '@now("yyyy")',
//部门
'college': '机电工程系',
//专业
'major': '机械制造与自动化',
//部门
'grade': '机制1班',
//辅导员
'tutor': '王刚',
},
{
'id|+1': 11,
//学生姓名
'name': '@cname',
//学生学号
'studentNumber': '@integer(188000000,18899999999)',
//性别
'gender': '@pick(["男","女"])',
//年龄
'age': '@integer(20,21)',
'tuition': 16800,
//减免金额
'mitigate': 10000,
//入学时间
'enrollmentyear': '@now("yyyy")',
//部门
'college': '护理分院',
//专业
'major': '护理学',
//部门
'grade': '护理学1班',
//辅导员
'tutor': '张明',
},
{
'id|+1': 21,
//学生姓名
'name': '@cname',
//学生学号
'studentNumber': '@integer(186000000,1869999999)',
//性别
'gender': '@pick(["男","女"])',
//年龄
'age': '@integer(20,21)',
'tuition': 16800,
//减免金额
'mitigate': 12000,
//入学时间
'enrollmentyear': '@now("yyyy")',
//部门
'college': '建筑系',
//专业
'major': '建筑工程',
//部门
'grade': '建筑1班',
//辅导员
'tutor': '李宇',
}
]
})
const premium = Mock.mock({
'list|10': [
{
'id|+1': 1,
//学生姓名
'name': '@cname',
//学生学号
'studentNumber': '@integer(132000000,1329999999)',
//性别
'gender': '@pick(["男","女"])',
//年龄
'age': '@integer(20,21)',
//退费金额
'tuition': 16800,
//入学时间
'enrollmentyear': '@now("yyyy")',
//部门
'college': '机电工程系',
//专业
'major': '机械制造与自动化',
//部门
'grade': '机制1班',
//辅导员
'tutor': '王刚',
},
{
'id|+1': 11,
//学生姓名
'name': '@cname',
//学生学号
'studentNumber': '@integer(188000000,18899999999)',
//性别
'gender': '@pick(["男","女"])',
//年龄
'age': '@integer(20,21)',
//退费金额
'tuition': 16800,
//入学时间
'enrollmentyear': '@now("yyyy")',
//部门
'college': '护理分院',
//专业
'major': '护理学',
//部门
'grade': '护理学1班',
//辅导员
'tutor': '张明',
},
{
'id|+1': 21,
//学生姓名
'name': '@cname',
//学生学号
'studentNumber': '@integer(186000000,1869999999)',
//性别
'gender': '@pick(["男","女"])',
//年龄
'age': '@integer(20,21)',
//退费金额
'tuition': 16800,
//入学时间
'enrollmentyear': '@now("yyyy")',
//部门
'college': '建筑系',
//专业
'major': '建筑工程',
//部门
'grade': '建筑1班',
//辅导员
'tutor': '李宇',
}
]
})
export default [
//应收管理列表
{
url: '/get-sdy-managment-list',
method: 'get',
response: () => {
return {
code: 200,
data: data
}
}
},
// 应收管理搜索
{
url: '/post-sdy-managment-find',
method: 'post',
response: (req) => {
if (req.body.name !== '') {
return data.list.filter(item => item.name.includes(req.body.name))
}
else if (req.body.studentnumber !== '') {
const studentnumber = Number(req.body.studentnumber)
if (!isNaN(studentnumber)) {
return data.list.filter(item => item.studentnumber === studentnumber)
} else {
return {
code: 400,
message: 'Invalid student number format'
}
}
}
else if (req.body.department !== '') {
return data.list.filter(item => item.department.includes(req.body.department))
}
else if (req.body.major !== '') {
return data.list.filter(item => item.major.includes(req.body.major))
}
else if (req.body.grade !== '') {
return data.list.filter(item => item.grade.includes(req.body.grade))
}
else if (req.body.tuition !== '') {
return data.list.filter(item => item.tuition.includes(req.body.tuition))
}
return {
code: 200,
}
}
},
// 借款管理
{
url: '/get-sdy-loan-list',
method: 'get',
response: () => {
return {
code: 200,
data: loans
}
}
},
// 借款管理搜索
{
url: '/post-sdy-loan-find',
method: 'post',
response: (req) => {
if (req.body.name !== '') {
const arr = loans.list.filter(item => item.proposer.includes(req.body.name))
return arr
} else if (req.body.studentnumber !== '') {
const studentnumber = Number(req.body.studentnumber)
const arr = loans.list.filter(item => item.student === studentnumber)
return arr
}
return {
code: 200,
data: arr
}
}
},
// 添加借款人
{
url: '/post-sdy-loan-add',
method: 'post',
response: (req) => {
const newLoan = {
id: loans.list.length + 1,
proposer: req.body.proposer,
student: req.body.student,
allowance: req.body.allowance,
department: req.body.department,
cation: req.body.cation,
loanTerm: req.body.loanTerm,
timeofapplication: req.body.timeofapplication,
}
loans.list.push(newLoan)
return {
code: 200,
data: newLoan
}
}
},
// 当日明细列表
{
url: '/get-sdy-daily-list',
method: 'get',
response: () => {
return {
code: 200,
data: daily
}
}
},
// 学生催款表
{
url: '/get-sdy-paragraph-list',
method: 'get',
response: () => {
return {
code: 200,
data: paragraph
}
}
},
// 学生催款表搜索
{
url: '/post-sdy-paragraph-find',
method: 'post',
response: (req) => {
if (req.body.name !== '') {
const arr = paragraph.list.filter(item => item.name.includes(req.body.name))
return arr
} else if (req.body.studentnumber !== '') {
const arr = paragraph.list.filter(item => item.department.includes(req.body.studentnumber))
return arr
} else if (req.body.counselor !== '') {
const arr = paragraph.list.filter(item => item.counselor.includes(req.body.counselor))
return arr
} else if (req.body.tutor !== '') {
const arr = paragraph.list.filter(item => item.grade.includes(req.body.tutor))
return arr
}
return {
code: 200,
data: arr
}
}
},
// 学院分析
{
url: '/get-sdy-analysis-list',
method: 'get',
response: () => {
return {
code: 200,
data: analysis
}
}
},
// 学生信息统计
{
url: '/get-sdy-message-list',
method: 'get',
response: () => {
return {
code: 200,
data: message
}
}
},
// 学生信息统计搜索
{
url: '/post-sdy-message-find',
method: 'post',
response: (req) => {
if (req.body.name !== '') {
const arr = message.list.filter(item => item.name.includes(req.body.name))
return arr
} else if (req.body.studentnumber !== '') {
const arr = message.list.filter(item => item.department.includes(req.body.studentnumber))
return arr
} else if (req.body.college !== '') {
const arr = message.list.filter(item => item.counselor.includes(req.body.counselor))
return arr
} else if (req.body.grade !== '') {
const arr = message.list.filter(item => item.grade.includes(req.body.grade))
return arr
}
return {
code: 200,
data: arr
}
}
},
// 减免管理
{
url: '/get-sdy-mitigate-list',
method: 'get',
response: () => {
return {
code: 200,
data: mitigate
}
}
},
// 减免管理搜索
{
url: '/post-sdy-mitigate-find',
method: 'post',
response: (req) => {
if (req.body.name !== '') {
const arr = mitigate.list.filter(item => item.name.includes(req.body.name))
return arr
} else if (req.body.studentnumber !== '') {
const arr = mitigate.list.filter(item => item.department.includes(req.body.studentnumber))
return arr
} else if (req.body.college !== '') {
const arr = mitigate.list.filter(item => item.counselor.includes(req.body.counselor))
return arr
} else if (req.body.tutor !== '') {
const arr = mitigate.list.filter(item => item.tutor.includes(req.body.tutor))
return arr
}
return {
code: 200,
data: arr
}
}
},
// 退费管理
{
url: '/get-sdy-premium-list',
method: 'get',
response: () => {
return {
code: 200,
data: premium
}
}
},
// 退费管理搜索
{
url: '/post-sdy-premium-find',
method: 'post',
response: (req) => {
if (req.body.name !== '') {
const arr = premium.list.filter(item => item.name.includes(req.body.name))
return arr
} else if (req.body.studentnumber !== '') {
const arr = premium.list.filter(item => item.department.includes(req.body.studentnumber))
return arr
} else if (req.body.college !== '') {
const arr = premium.list.filter(item => item.counselor.includes(req.body.counselor))
return arr
} else if (req.body.tutor !== '') {
const arr = premium.list.filter(item => item.tutor.includes(req.body.tutor))
return arr
}
return {
code: 200,
data: arr
}
}
},
]

279
mock/modules/ycy.js Normal file
View File

@ -0,0 +1,279 @@
import Mock from "mockjs";
// 入库列表
const StockList = Mock.mock({
"list|20-30": [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
billType: "@integer(0,4)",
stockNum: "@integer(1,2)",
stockDate: "@date",
operator: "@cname",
remark: " @integer(10000000000,19999999999)",
},
],
});
// 领用列表
const ReceiptList = Mock.mock([
{
"list|20-30": [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
proposer: "孙东宇",
billType: "@integer(0,4)",
receiptNum: "@integer(1,10)",
receiptDate: "@date",
useInfo: "@csentence",
},
],
},
{
"list|20-30": [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
proposer: "杨春宇",
billType: "@integer(0,4)",
receiptNum: "@integer(1,10)",
receiptDate: "@date",
useInfo: "@csentence",
},
],
},
{
"list|20-30": [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
proposer: "吕才卓",
billType: "@integer(0,4)",
receiptNum: "@integer(1,10)",
receiptDate: "@date",
useInfo: "@csentence",
},
],
},
{
"list|20-30": [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
proposer: "刘欣宇",
billType: "@integer(0,4)",
receiptNum: "@integer(1,10)",
receiptDate: "@date",
useInfo: "@csentence",
},
],
},
]);
// 退领列表
const quitneckList = Mock.mock([
{
list: [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
proposer: "孙东宇",
billType: "@integer(0,4)",
receiptNum: "@integer(1,10)",
receiptDate: "@date",
useInfo: "@csentence",
},
],
},
{
list: [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
proposer: "杨春宇",
billType: "@integer(0,4)",
receiptNum: "@integer(1,10)",
receiptDate: "@date",
useInfo: "@csentence",
},
],
},
{
list: [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
proposer: "吕才卓",
billType: "@integer(0,4)",
receiptNum: "@integer(1,10)",
receiptDate: "@date",
useInfo: "@csentence",
},
],
},
{
list: [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
proposer: "刘欣宇",
billType: "@integer(0,4)",
receiptNum: "@integer(1,10)",
receiptDate: "@date",
useInfo: "@csentence",
},
],
},
]);
// 人员名单
const personName = () => {
return [
{
label: "员工名单",
children: [
{
label: "孙东宇",
},
{
label: "杨春宇",
},
{
label: "吕才卓",
},
{
label: "刘欣宇",
},
],
},
];
};
// 退库列表
const CancelList = Mock.mock({
"list|20-30": [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
billType: "@integer(0,4)",
cancelNum: "@integer(1,10)张",
appleDate: "@date",
proposer: "@cname",
approvalStatus: "@integer(0,3)",
reason: " @integer(10000000000,19999999999)",
},
],
});
// 报损列表
const breakageList = Mock.mock({
"list|20-30": [
{
"id|+1": 0,
billserial: "@integer(100000000,199999999)1",
billType: "@integer(0,4)",
breakNum: "@integer(1,2)",
breakDate: "@date",
operator: "@cname",
breakStatus: "@integer(0,2)",
breakInfo: "@csentence",
},
],
});
//
const detailReportList = Mock.mock({
"list|5": [
{
"id|+1": 0,
branch: "@cname",
stockNum: "@integer(1,20)张",
cancelNum: "@integer(0,20)张",
receiveNum: "@integer(0,20)张",
breakNum: "@integer(0,20)张",
destoryNum: "@integer(0,20)张",
grossBillRatio: "25%",
},
],
});
export default [
{
url: "/api/stockList",
method: "get",
response: () => {
return {
code: 200,
data: StockList,
};
},
},
{
url: "/api/cancelList",
method: "get",
response: () => {
return {
code: 200,
data: CancelList,
};
},
},
{
url: "/api/personName",
method: "get",
response: () => {
const list = personName();
return {
code: 200,
data: list,
};
},
},
{
url: "/api/receiptList",
method: "post",
response: (req) => {
if (req.body.name === "孙东宇") {
return {
code: 200,
data: ReceiptList[0].list,
};
} else if (req.body.name === "杨春宇") {
return {
code: 200,
data: ReceiptList[1].list,
};
} else if (req.body.name === "吕才卓") {
return {
code: 200,
data: ReceiptList[2].list,
};
} else {
return {
code: 200,
data: ReceiptList[3].list,
};
}
},
},
{
url: "/api/breakageList",
method: "get",
response: () => {
return {
code: 200,
data: breakageList,
};
},
},
{
url: "/api/detailReportList",
method: "get",
response: () => {
return {
code: 200,
data: detailReportList,
};
},
},
];

4181
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,16 +10,28 @@
}, },
"dependencies": { "dependencies": {
"axios": "^1.6.8", "axios": "^1.6.8",
"dayjs": "^1.11.10",
"echarts": "^5.5.0",
"exceljs": "^4.4.0",
"file-saver": "^2.0.5",
"less": "^4.2.0", "less": "^4.2.0",
"mockjs": "^1.1.0", "mockjs": "^1.1.0",
"pdfmake": "^0.2.10",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.1",
"prettier": "^3.2.5",
"sortablejs": "^1.15.2",
"tdesign-vue-next": "^1.9.3", "tdesign-vue-next": "^1.9.3",
"vite-plugin-mock": "^3.0.1",
"vue": "^3.4.21", "vue": "^3.4.21",
"vue-draggable-plus": "^0.4.0",
"vue-router": "^4.3.0" "vue-router": "^4.3.0"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^5.0.4", "@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0", "@vitejs/plugin-vue-jsx": "^3.1.0",
"gulp": "^5.0.0",
"sass": "^1.74.1",
"vite": "^5.1.6" "vite": "^5.1.6"
} }
} }

8
prettier.json Normal file
View File

@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth":200,
"trailingComma": "none"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,7 @@
import request from "@/utils/requestMock";
const API = {
BACKAGE_LIST: "/breakageList",
};
export const reqBreakageList = () => request.get(API.BACKAGE_LIST);

View File

@ -0,0 +1,7 @@
import request from "@/utils/requestMock";
const API = {
CANCEL_LIST: "/cancelList",
};
export const reqCancelList = () => request.get(API.CANCEL_LIST);

View File

@ -0,0 +1,7 @@
import request from "@/utils/requestMock";
const API = {
DETAILREPORT_LIST: "/detailReportList",
};
export const reqDetailReportList = () => request.get(API.DETAILREPORT_LIST);

View File

@ -0,0 +1,9 @@
import request from "@/utils/requestMock";
const API = {
PERSON_LIST: "/personName",
RECEIPT_LIST: "/receiptList",
};
export const reqPersonName = () => request.get(API.PERSON_LIST);
export const reqReceiptList = (data) => request.post(API.RECEIPT_LIST, data);

View File

@ -0,0 +1,7 @@
import request from "@/utils/requestMock";
const API = {
STOCK_LIST: "/stockList",
};
export const reqStockList = () => request.get(API.STOCK_LIST);

8
src/api/login.js Normal file
View File

@ -0,0 +1,8 @@
import request from "@/utils/request";
// 统一管理接口
const API = {
LOGIN_URL: "/api/login",
};
export const reqUser = (data) => request.post(API.LOGIN_URL,data);
// export const reqUserone = (data) => request.post(API.LOGIN_URL, data);

7
src/api/password.js Normal file
View File

@ -0,0 +1,7 @@
import request from "@/utils/request";
// 统一管理接口
const API = {
PASSWORD_URL: "/api/password",
};
export const reqPassword = () => request.post(API.PASSWORD_URL);

View File

@ -0,0 +1,61 @@
import request from '@/utils/request'
// 收款管理
export function APIReceivablesList() {
return request.get('/get-sdy-managment-list')
}
//查询收款
export function APIReceivablesAdd(data) {
return request.post('/post-sdy-managment-find', data)
}
//贷款管理
export function APILoansList() {
return request.get('/get-sdy-loan-list')
}
//查询贷款
export function APILoansFind(data) {
return request.post('/post-sdy-loan-find', data)
}
//添加贷款
export function APILoansAdd(data) {
return request.post('/post-sdy-loan-add', data)
}
// 借款管理
export function APIDailyList() {
return request.get('/get-sdy-daily-list')
}
//催缴管理
export function APIParagraphList() {
return request.get('/get-sdy-paragraph-list')
}
//催缴搜索
export function APIParagraphFind(data) {
return request.post('/post-sdy-paragraph-find', data)
}
//学院分析
export function APIAnalysisList() {
return request.get('/get-sdy-analysis-list')
}
//学生信息统计
export function APIMessageList() {
return request.get('/get-sdy-message-list')
}
//学生信息搜索
export function APIMessageFind(data) {
return request.post('/post-sdy-message-find', data)
}
//减免管理
export function APIMitigateList() {
return request.get('/get-sdy-mitigate-list')
}
//减免搜索
export function APIMitigateFind(data) {
return request.post('/post-sdy-mitigate-find', data)
}
// 退费管理
export function APIPremiumList() {
return request.get('/get-sdy-premium-list')
}
//退费搜索
export function APIPremiumFind(data) {
return request.post('/post-sdy-premium-find', data)
}

18
src/api/students.js Normal file
View File

@ -0,0 +1,18 @@
import request from '@/utils/request'
export function getList() {
return request.get('/api-list')
}
export function getStudents(studentData) {
return request.post('/api-student', studentData)
}
export function updateStudent(updateStudent) {
return request.post('/api-updateStudent', updateStudent)
}
// const API = {
// STUDENT_URL: "/api/user",
// };
// export const reqStudent = () => request.get(API.STUDENT_URL);

BIN
src/assets/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

BIN
src/assets/bg1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@ -0,0 +1,89 @@
<template>
<div style="height: 100%">
<div ref="barChartRef" :style="{ width: width, height: height }"></div>
</div>
</template>
<script setup>
import * as echarts from "echarts";
import { onMounted, ref } from "vue";
//
const barChartRef = ref(null);
const { categories, seriesData, title, legendList } = defineProps({
//
categories: {
type: Array,
required: true,
},
//
seriesData: {
type: Array,
required: true,
},
//
title: {
type: String,
required: true,
},
//
legendList: {
type: Array,
required: true,
},
//
width: {
type: String,
default: "100%",
},
//
height: {
type: String,
default: "100%",
},
});
//
const option = {
title: {
text: title,
left: "center",
top: "10",
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
legend: {
data: legendList, //
bottom: "10",
},
xAxis: {
type: "category",
data: categories,
},
yAxis: {
type: "value",
},
series: seriesData,
};
// ECharts
onMounted(() => {
const barChartContainer = barChartRef.value;
if (barChartContainer) {
const myChart = echarts.init(barChartContainer);
myChart.setOption(option);
// resize
window.addEventListener("resize", () => {
myChart.resize();
});
}
});
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,117 @@
<template>
<div style="height: 100%">
<div ref="lineChartRef" :style="{ width: width, height: height }">
111111
</div>
</div>
</template>
<script setup>
import * as echarts from "echarts";
import { onMounted, ref } from "vue";
//
const lineChartRef = ref(null);
const { categories, seriesData, titleP, legendList } = defineProps({
//
categories: {
type: Array,
required: true,
},
//
seriesData: {
type: Array,
required: true,
},
titleP: {
type: String,
default: "示例折线图",
},
//
legendList: {
type: Array,
required: true,
},
width: {
type: String,
default: "100%",
},
height: {
type: String,
default: "100%",
},
});
//
const option = {
title: {
text: titleP,
left: "center",
top: "2",
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "cross",
label: {
backgroundColor: "#6a7985",
},
},
},
legend: {
data: legendList,
bottom: 0,
},
grid: {
left: "3%",
right: "3%",
bottom: "9%",
containLabel: true,
},
xAxis: {
type: "category",
boundaryGap: false,
data: categories,
axisTick: {
alignWithLabel: true,
},
},
yAxis: {
type: "value",
splitLine: {
lineStyle: {
type: "dashed",
},
},
},
series: seriesData.map((serie, index) => ({
...serie,
lineStyle: {
width: 2,
},
smooth: true,
itemStyle: {
color: `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${
Math.random() * 255
}, 0.8)`,
},
})),
};
// ECharts
onMounted(() => {
const lineChartContainer = lineChartRef.value;
if (lineChartContainer) {
const myChart = echarts.init(lineChartContainer);
myChart.setOption(option);
// resize
window.addEventListener("resize", () => {
myChart.resize();
});
}
});
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,82 @@
<template>
<div>
<div ref="pieChartRef" :style="{ width: width, height: height }"></div>
</div>
</template>
<script setup>
import * as echarts from "echarts";
import { onMounted, ref } from "vue";
//
const pieChartRef = ref(null);
const { titleP, dataP } = defineProps({
//
dataP: {
type: Array,
default: () => [],
},
titleP: {
type: String,
default: "",
},
width: {
type: String,
default: "100%",
},
height: {
type: String,
default: "100%",
},
});
//
const option = {
title: {
text: titleP,
left: "center",
},
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b}: {c} ({d}%)",
},
legend: {
orient: "vertical",
left: "0",
top: "50",
},
series: [
{
name: "访问来源",
type: "pie",
radius: "50%",
left: "50",
data: dataP,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)",
},
},
},
],
};
// ECharts
onMounted(() => {
const pieChartContainer = pieChartRef.value;
if (pieChartContainer) {
const myChart = echarts.init(pieChartContainer);
myChart.setOption(option);
// resize
window.addEventListener("resize", () => {
myChart.resize();
});
}
});
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,44 @@
<template>
<t-row style="width: 100%">
<t-col :span="colNum">
<t-row :gutter="[24, 24]" style="margin-left: 0.3rem">
<slot name="scarchName"> </slot>
</t-row>
</t-col>
<t-col :span="btnNum" class="operation-container">
<t-form-item style="margin-right: 1rem">
<slot name="scarchBtn"> </slot>
</t-form-item>
</t-col>
</t-row>
</template>
<script setup>
import { number } from "echarts";
const { colNum, btnNum } = defineProps({
colNum: {
type: Number,
default: 10,
},
btnNum: {
type: Number,
default: 2,
},
});
</script>
<style scoped lang="less">
.operation-container {
display: flex;
justify-content: flex-end;
align-items: center;
.expand {
.t-button__text {
display: flex;
align-items: center;
}
}
}
</style>

View File

@ -0,0 +1,105 @@
<template>
<div style="height: 100%">
<t-menu style="height: 92vh">
<t-submenu value="1" title="首页">
<template #icon>
<t-icon name="home" />
</template>
<t-menu-item value="1-1" to="/home">
<span>首页</span>
</t-menu-item>
</t-submenu>
<t-submenu value="2" title="财务票据管理">
<template #icon>
<t-icon name="application" />
</template>
<t-menu-item value="2-1" to="/Bill/BillStock">
<span>票据入库</span>
</t-menu-item>
<t-menu-item value="2-2" to="/Bill/BillCancel">
<span>票据退库</span>
</t-menu-item>
<t-menu-item value="2-3" to="/Bill/BillReceipt">
<span>票据领用</span>
</t-menu-item>
<t-menu-item value="2-4" to="/Bill/BillQuitneck">
<span>票据退领</span>
</t-menu-item>
<t-menu-item value="2-5" to="/Bill/BillBreakagek">
<span>票据报损</span>
</t-menu-item>
<t-menu-item value="2-6" to="/Bill/BillDestroy">
<span>票据核销</span>
</t-menu-item>
<t-menu-item value="2-7" to="/Bill/DetailReport">
<span>报表明细</span>
</t-menu-item>
<t-menu-item value="2-8" to="/Bill/BillDraw">
<span>票据列表</span>
</t-menu-item>
<t-menu-item value="2-9" to="/Bill/drag">
<span>拖拽效果</span>
</t-menu-item>
</t-submenu>
<t-submenu value="3" title="应收款管理">
<template #icon>
<t-icon name="application" />
</template>
<t-menu-item value="3-1" to="/accounts">
<span>应收款管理</span>
</t-menu-item>
<t-menu-item value="3-2" to="/billCollected">
<span>学生收款</span>
</t-menu-item>
<t-menu-item value="3-3" to="/student-loan">
<span>助学贷款</span>
</t-menu-item>
<t-menu-item value="3-4" to="/daily">
<span>收费日报表</span>
</t-menu-item>
<t-menu-item value="3-5" to="/mitigate">
<span>减免明细表</span>
</t-menu-item>
<t-menu-item value="3-6" to="/return-premium">
<span>退费明细表</span>
</t-menu-item>
<t-menu-item value="3-7" to="/rrrearage">
<span>欠费明细表</span>
</t-menu-item>
<t-menu-item value="3-8" to="/charge-schedule">
<span>学生催款单</span>
</t-menu-item>
<t-menu-item value="3-9" to="/faculty-analysis">
<span>部门分析表</span>
</t-menu-item>
<t-menu-item value="3-10" to="/student-information">
<span>学生信息统计表</span>
</t-menu-item>
<t-menu-item value="3-11" to="/shi-yan">
<span>实验</span>
</t-menu-item>
</t-submenu>
<t-submenu value="4" title="学生管理">
<template #icon>
<t-icon name="application" />
</template>
<t-menu-item value="4-1" to="/Students">
<span>学生管理</span>
</t-menu-item>
</t-submenu>
</t-menu>
</div>
</template>
<script setup></script>
<style lang="less" scoped>
.t-demo-collapse-btn {
color: #fff;
&:hover {
background-color: #4b4b4b;
border-color: transparent;
--ripple-color: #383838;
}
}
</style>

View File

@ -0,0 +1,14 @@
<template>
<div>
<t-layout>
<t-content>
<RouterView />
</t-content>
<!-- <t-footer style="height: 2px">Footer</t-footer> -->
</t-layout>
</div>
</template>
<script setup></script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,58 @@
<template>
<div>
<t-head-menu v-model="menu1Value" theme="light" @change="changeHandler">
<template #logo>
<img
height="28"
src="https://tdesign.gtimg.com/site/baseLogo-light.png"
alt="logo"
/>
</template>
<t-menu-item value="item1"> 菜单1 </t-menu-item>
<t-menu-item value="item2"> 菜单2 </t-menu-item>
<t-menu-item value="item4" :disabled="true"> 禁用菜单 </t-menu-item>
<template #operations>
<t-button variant="text" shape="square">
<template #icon><t-icon name="search" /></template>
</t-button>
<t-button variant="text" shape="square">
<template #icon><t-icon name="mail" /></template>
</t-button>
<t-button variant="text" shape="square">
<template #icon><t-icon name="user" /></template>
</t-button>
<t-button variant="text" shape="square">
<template #icon><t-icon name="ellipsis" /></template>
</t-button>
</template>
</t-head-menu>
</div>
</template>
<script setup>
import { ref } from 'vue'
const menu1Value = ref('item2')
const changeHandler = active => {
console.log('change', active)
}
</script>
<style lang="less" scoped>
.t-menu__operations {
.t-button {
margin-left: 8px;
}
}
.t-demo-menu--dark {
.t-button {
color: #fff;
&:hover {
background-color: #4b4b4b;
border-color: transparent;
--ripple-color: #383838;
}
}
}
</style>

View File

@ -0,0 +1,22 @@
<template>
<t-layout>
<t-header>
<LHeader />
</t-header>
<t-layout>
<t-aside>
<LAside />
</t-aside>
<t-content>
<LContent />
</t-content>
</t-layout>
</t-layout>
</template>
<script setup>
import LHeader from "./components/LayoutHeader.vue";
import LAside from "./components/LayoutAside.vue";
import LContent from "./components/LayoutContent.vue";
</script>
<style scoped></style>

View File

@ -1,16 +1,19 @@
import './style/index.css' import "./style/index.css";
import { createApp } from 'vue' import { createApp } from "vue";
import { createPinia } from 'pinia' import { createPinia } from "pinia";
import TDesign from 'tdesign-vue-next'; import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
import TDesign from "tdesign-vue-next";
import App from './App.vue' import App from "./App.vue";
import router from './router' import router from "./router";
const app = createApp(App) const app = createApp(App);
app.use(createPinia()) const pinia = createPinia();
app.use(router) pinia.use(piniaPluginPersistedstate);
app.use(pinia);
app.use(router);
app.use(TDesign); app.use(TDesign);
app.mount('#app') app.mount("#app");

View File

@ -0,0 +1,377 @@
<template>
<div class="back-color">
<t-layout style="height: 90%; background-color: #f5f7fb">
<t-header class="scarch-box">
<t-form
ref="form"
:data="formData"
label-width="calc(2em + 40px)"
layout="inline"
scroll-to-first-error="smooth"
class="scarch-from"
@reset="resetting"
@submit="headerQuery"
>
<scarch-box :btnNum="4" :colNum="8">
<template #scarchName>
<t-col :span="3">
<t-form-item label="票据编号:" name="billserial">
<t-input class="form-item-content" v-model="formData.billserial" maxlength="10"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="报损日期:" name="breakDate">
<t-date-picker class="form-item-content" v-model="formData.breakDate" clearable />
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="票据类型:" name="billType">
<t-select class="form-item-content" v-model="formData.billType" placeholder="请选择票据类型" clearable>
<t-option v-for="item in billType" :key="item.value" :value="item.value" :label="item.label"></t-option>
</t-select>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="报损状态:" name="breakStatus" style="margin-bottom: 0.3rem">
<t-select class="form-item-content" v-model="formData.breakStatus" placeholder="请选择报损状态" clearable>
<t-option v-for="item in billStatus" :key="item.value" :value="item.value" :label="item.label"></t-option>
</t-select>
</t-form-item>
</t-col>
</template>
<template #scarchBtn>
<t-button theme="primary" type="submit">查询</t-button>
<t-button theme="default" type="reset">重置</t-button>
</template>
</scarch-box>
</t-form>
</t-header>
<t-content class="table-box">
<div class="table-header">
<div>
<h4 style="font-size: 110%">票据报损列表</h4>
</div>
<div>
<t-button theme="primary" size="small" @click="breakageAdd">
<template #icon><add-icon /></template>
新增报损票据
</t-button>
<t-button shape="circle" theme="primary" @click="refresh" style="margin-left: 0.8rem">
<template #icon><load-icon /></template>
</t-button>
</div>
</div>
<t-base-table
hover
row-key="index"
:loading="loading"
:data="tableData"
:columns="columns"
:pagination="pagination"
class="table"
:max-height="550"
>
<template #status="slotProps">
<t-button
theme="default"
variant="text"
size="small"
@click="breakEdit(slotProps)"
:disabled="slotProps.row.breakStatus === 0 || slotProps.row.breakStatus === 1"
>修改</t-button
>
<t-popconfirm content="确认删除吗" @confirm="breakDelete(slotProps)">
<t-button theme="default" variant="text" size="small" :disabled="slotProps.row.breakStatus === 0">删除</t-button>
</t-popconfirm>
</template>
</t-base-table>
</t-content>
</t-layout>
<t-space>
<t-dialog
ref="postForm"
v-model:visible="visiblePost"
:header="headerTitle"
width="40%"
:confirm-on-enter="true"
:on-close="closePost"
:confirm-btn="null"
:cancel-btn="null"
>
<list-form :activeForm="'break'" @childForm="breakEvent" :editFrom="editFrom" />
</t-dialog>
</t-space>
</div>
</template>
<script setup lang="jsx">
import scarchBox from "@/components/scarchBox.vue";
import listForm from "./form/index.vue";
import { billType, billStatus } from "./codeValue/index";
import { ref, onMounted } from "vue";
import { MessagePlugin } from "tdesign-vue-next";
import { AddIcon, LoadIcon } from "tdesign-icons-vue-next";
import { useBreakage } from "@/stores/billBreakage";
//
const loading = ref(false);
const visiblePost = ref(false);
const breakageList = useBreakage();
const tableData = ref([]);
const data = ref([]);
const headerTitle = ref("");
const editFrom = ref();
//
const columns = ref([
{
colKey: "serial-number",
title: "序号",
width: 50,
},
{
colKey: "billserial",
title: "票据编号",
align: "center",
width: "100",
},
{
colKey: "billType",
title: "票据类型",
align: "center",
width: "100",
cell: (h, { row }) => {
const type = billType.find((type) => type.value === row.billType);
return type ? type.label : "未知";
},
},
{
colKey: "breakNum",
title: "报损数量",
align: "center",
width: "100",
cell: (h, { row }) => {
return row.breakNum + "张";
},
},
{
colKey: "breakDate",
title: "报损日期",
align: "center",
width: "100",
},
{
colKey: "operator",
title: "操作员",
align: "center",
width: "100",
},
{
colKey: "breakStatus",
title: "报损状态",
align: "center",
width: "100",
cell: (h, { row }) => {
const status = billStatus.find((item) => item.value === row.breakStatus);
return (
<t-tag theme={tagColor(row.breakStatus)} variant="light">
{status.label}
</t-tag>
);
},
},
{
colKey: "breakInfo",
title: "报损原因",
ellipsis: true,
align: "center",
width: "100",
},
{
colKey: "status",
title: "操作",
width: 120,
align: "center",
fixed: "right",
},
]);
//
const tableList = async () => {
loading.value = true;
tableData.value = await breakageList.getBreakageList();
data.value = await breakageList.getBreakageList();
pagination.value.total = tableData.value.length;
const timerId = setTimeout(() => {
loading.value = false;
clearInterval(timerId);
}, 300);
};
// tag
const tagColor = (value) => {
switch (value) {
case 0:
return "warning";
case 1:
return "success";
case 2:
return "danger";
}
};
//
const refresh = () => {
tableList();
};
//
const formData = ref({
billserial: "",
billType: "",
breakStatus: "",
breakDate: "",
});
//
const pagination = ref({
defaultCurrent: 1,
defaultPageSize: 10,
total: 50,
});
//
const resetting = () => {
formData.value = {
billserial: "",
billType: "",
breakStatus: "",
breakDate: "",
};
getNewTable();
};
//
const headerQuery = () => {
tableData.value = data.value;
if (
formData.value.billserial === "" &&
(formData.value.billType === undefined || formData.value.billType === "") &&
(formData.value.breakStatus === undefined || formData.value.breakStatus === "") &&
formData.value.breakDate === ""
) {
getNewTable();
} else {
const list = tableData.value.filter((item) => {
let arrList;
if (formData.value.billserial === item.billserial) {
arrList = item;
}
if (formData.value.billType === item.billType) {
arrList = item;
}
if (formData.value.breakStatus === item.breakStatus) {
arrList = item;
}
if (formData.value.breakDate === item.breakDate) {
arrList = item;
}
if (
formData.value.billserial === "" &&
formData.value.billType === "" &&
formData.value.breakStatus === "" &&
formData.value.breakDate === ""
) {
arrList = item;
}
return arrList;
});
tableData.value = list;
// @ts-expect-error
pagination.value.total = list.length;
}
};
//
const breakageAdd = () => {
visiblePost.value = true;
headerTitle.value = "新增报损票据";
};
//
const closePost = () => {
visiblePost.value = false;
};
//
const breakEvent = async (data) => {
data.breakStatus = 0;
await breakageList.addBreakageList(data);
getNewTable();
MessagePlugin.success("提交成功");
visiblePost.value = false;
};
//
const breakEdit = (item) => {
headerTitle.value = "修改报损票据";
visiblePost.value = true;
tableData.value.forEach((itemTable) => {
if (itemTable.id === item.row.id) {
editFrom.value = itemTable;
}
});
};
//
const breakDelete = async (itme) => {
await breakageList.deleteBreakageList(itme.row);
getNewTable();
};
//
const onReset = () => {};
// menuManagement
const getNewTable = () => {
let arr = JSON.parse(localStorage.getItem("breakageList"));
if (arr) {
tableData.value = arr.breakageList;
data.value = arr.breakageList;
pagination.value.total = tableData.value.length;
} else {
tableList();
}
};
onMounted(() => {
getNewTable();
});
</script>
<style scoped lang="less">
.scarch-box {
width: 100%;
background-color: @base-white-color;
margin-bottom: 2rem;
.scarch-from {
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.table-box {
height: 42rem;
background-color: @base-white-color;
padding: 1rem;
padding-top: 0;
.table-header {
height: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
}
}
:deep(.t-form__controls-content) {
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,357 @@
<template>
<div class="back-color">
<t-layout style="height: 90%; background-color: #f5f7fb">
<t-header class="scarch-box">
<t-form
ref="form"
:data="scarchData"
label-width="calc(2em + 40px)"
layout="inline"
scroll-to-first-error="smooth"
class="scarch-from"
@reset="resetting"
@submit="headerQuery"
>
<scarch-box :btnNum="4" :colNum="8">
<template #scarchName>
<t-col :span="3">
<t-form-item label="票据编号:" name="billserial">
<t-input class="form-item-content" v-model="scarchData.billserial" maxlength="10"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="退库日期:" name="appleDate">
<t-date-picker class="form-item-content" v-model="scarchData.appleDate" clearable />
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="票据类型:" name="billType">
<t-select class="form-item-content" v-model="scarchData.billType" placeholder="请选择票据类型" clearable>
<t-option v-for="item in billType" :key="item.value" :value="item.value" :label="item.label"></t-option>
</t-select>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="审批状态:" name="approvalStatus" style="margin-bottom: 0.3rem">
<t-select class="form-item-content" v-model="scarchData.approvalStatus" placeholder="请选择审批状态" clearable>
<t-option v-for="item in exaStatus" :key="item.value" :value="item.value" :label="item.label"></t-option>
</t-select>
</t-form-item>
</t-col>
</template>
<template #scarchBtn>
<t-button theme="primary" type="submit">查询</t-button>
<t-button theme="default" type="reset">重置</t-button>
</template>
</scarch-box>
</t-form>
</t-header>
<t-content class="table-box">
<div class="table-header">
<div>
<h4 style="font-size: 110%">票据退库列表</h4>
</div>
<div>
<t-button shape="circle" theme="primary" @click="refresh" style="margin-left: 0.8rem">
<template #icon><load-icon /></template>
</t-button>
</div>
</div>
<t-base-table
hover
row-key="index"
:loading="loading"
:data="tableData"
:columns="columns"
:pagination="pagination"
class="table"
:max-height="550"
>
<template #status="slotProps">
<t-button theme="default" variant="text" size="small" @click="Approve(slotProps)">
<span v-if="slotProps.row.approvalStatus === 0">{{ "审批" }}</span>
<span v-if="slotProps.row.approvalStatus === 3">{{ "重新审批" }}</span>
</t-button>
</template>
</t-base-table>
</t-content>
</t-layout>
<t-space>
<t-dialog
ref="postForm"
v-model:visible="visiblePost"
header="审批"
width="40%"
:confirm-on-enter="true"
:on-close="closePost"
:confirm-btn="null"
:cancel-btn="null"
>
<list-form :activeForm="'cancel'" @childForm="cancelromEvent" />
</t-dialog>
</t-space>
</div>
</template>
<script setup lang="jsx">
import scarchBox from "@/components/scarchBox.vue";
import listForm from "./form/index.vue";
import { billType, exaStatus } from "./codeValue/index.js";
import { ref, onMounted } from "vue";
import { MessagePlugin } from "tdesign-vue-next";
import { LoadIcon } from "tdesign-icons-vue-next";
import { useCancel } from "@/stores/billCancel";
//
const pagination = ref({
defaultCurrent: 1,
defaultPageSize: 10,
total: 50,
});
//
const scarchData = ref({
billserial: "",
billType: "",
appleDate: "",
approvalStatus: [],
});
//
const loading = ref(false);
const visiblePost = ref(false);
const cancelList = useCancel();
const tableData = ref([]);
const data = ref([]);
const headerTiTle = ref("");
//
const columns = ref([
{
colKey: "serial-number",
title: "序号",
width: 50,
},
{
colKey: "billserial",
title: "票据编号",
align: "center",
width: "100",
},
{
colKey: "billType",
title: "票据类型",
align: "center",
width: "100",
cell: (h, { row }) => {
const type = billType.find((type) => type.value === row.billType);
return type ? type.label : "未知";
},
},
{
colKey: "cancelNum",
title: "退库数量",
align: "center",
width: "100",
},
{
colKey: "appleDate",
title: "申请时间",
align: "center",
width: "100",
},
{
colKey: "proposer",
title: "申请人",
align: "center",
width: "100",
},
{
colKey: "approvalStatus",
title: "审批状态",
align: "center",
width: "100",
cell: (h, { row }) => {
const status = exaStatus.find((item) => item.value === row.approvalStatus);
return (
<t-tag theme={tagColor(row.approvalStatus)} variant="light">
{status.label}
</t-tag>
);
},
},
{
colKey: "reason",
title: "退库原因",
ellipsis: true,
align: "center",
width: "100",
},
{
colKey: "status",
title: "操作",
width: 120,
align: "center",
fixed: "right",
},
]);
//
const dialogData = ref({
approver: "",
approvalDate: "",
approvalReason: "",
});
//
const tableList = async () => {
loading.value = true;
tableData.value = await cancelList.getCancelList();
data.value = await cancelList.getCancelList();
pagination.value.total = tableData.value.length;
const timerId = setTimeout(() => {
loading.value = false;
clearInterval(timerId);
}, 300);
};
// tag
const tagColor = (value) => {
switch (value) {
case 0:
return "default";
case 1:
return "warning";
case 2:
return "success";
case 3:
return "danger";
}
};
//
const refresh = () => {
tableList();
};
//
const headerQuery = () => {
tableData.value = data.value;
if (
scarchData.value.billserial === "" &&
(scarchData.value.billType === undefined || scarchData.value.billType === "") &&
(scarchData.value.approvalStatus === undefined || scarchData.value.approvalStatus === "") &&
scarchData.value.appleDate === ""
) {
getNewTable();
} else {
const list = tableData.value.filter((item) => {
let arrList;
if (scarchData.value.billserial === item.billserial) {
arrList = item;
}
if (scarchData.value.billType === item.billType) {
arrList = item;
}
if (scarchData.value.approvalStatus === item.approvalStatus) {
arrList = item;
}
if (scarchData.value.appleDate === item.appleDate) {
arrList = item;
}
if (
scarchData.value.billserial === "" &&
scarchData.value.billType === "" &&
scarchData.value.appleDate === "" &&
scarchData.value.approvalStatus === ""
) {
arrList = item;
}
console.log(arrList);
return arrList;
});
tableData.value = list;
pagination.value.total = list.length;
}
};
//
const resetting = () => {
scarchData.value = {
billserial: "",
billType: "",
appleDate: "",
approvalStatus,
};
getNewTable();
};
const rowItem = ref({});
const Approve = (value) => {
dialogData.value = {
approver: "",
approvalDate: "",
approvalReason: "",
};
visiblePost.value = true;
rowItem.value = value;
};
//
const onReset = () => {};
//
const cancelromEvent = async () => {
rowItem.value.row.approvalStatus = 1;
await cancelList.editApprovalStatus(rowItem.value);
getNewTable();
MessagePlugin.success("提交成功");
visiblePost.value = false;
};
//
const closePost = () => {
visiblePost.value = false;
};
// menuManagement
const getNewTable = () => {
let arr = JSON.parse(localStorage.getItem("CancelList"));
if (arr) {
tableData.value = arr.cancelList;
data.value = arr.cancelList;
pagination.value.total = tableData.value.length;
} else {
tableList();
}
};
onMounted(() => {
getNewTable();
});
</script>
<style lang="less" scoped>
.scarch-box {
width: 100%;
background-color: @base-white-color;
margin-bottom: 2rem;
.scarch-from {
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.table-box {
height: 42rem;
background-color: @base-white-color;
padding: 1rem;
padding-top: 0;
.table-header {
height: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
}
}
:deep(.t-form__controls-content) {
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,314 @@
<template>
<div class="back-color">
<t-layout style="height: 90%; background-color: #f5f7fb">
<t-header class="scarch-box">
<t-form
ref="form"
:data="formData"
label-width="calc(2em + 40px)"
layout="inline"
scroll-to-first-error="smooth"
class="scarch-from form-responsive"
@reset="resetting"
@submit="headerQuery"
>
<scarch-box :btnNum="4" :colNum="8">
<template #scarchName>
<t-col :span="3">
<t-form-item label="票据编号:" name="billserial">
<t-input v-model="formData.billserial" class="form-item-content" maxlength="10"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="报损日期:" name="breakDate">
<t-date-picker v-model="formData.breakDate" class="form-item-content" clearable />
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="票据类型:" name="billType">
<t-select v-model="formData.billType" placeholder="请选择票据类型" class="form-item-content" clearable>
<t-option v-for="item in billType" :key="item.value" :value="item.value" :label="item.label"></t-option>
</t-select>
</t-form-item>
</t-col>
</template>
<template #scarchBtn>
<t-button theme="primary" type="submit">查询</t-button>
<t-button theme="default" type="reset">重置</t-button>
</template>
</scarch-box>
</t-form>
</t-header>
<t-content class="table-box">
<div class="table-header">
<div>
<h4 style="font-size: 110%">票据核销列表</h4>
</div>
<div>
<t-button shape="circle" theme="primary" @click="refresh" style="margin-left: 0.8rem">
<template #icon><load-icon /></template>
</t-button>
</div>
</div>
<t-base-table
hover
row-key="index"
:loading="loading"
:data="tableData"
:columns="columns"
:pagination="pagination"
class="table"
:height="550"
>
<template #status="slotProps">
<t-button theme="default" variant="text" size="small" @click="breakEdit(slotProps)">审核</t-button>
</template>
</t-base-table>
</t-content>
</t-layout>
<t-space>
<t-dialog
ref="postForm"
v-model:visible="visiblePost"
:header="headerTitle"
width="40%"
:confirm-on-enter="true"
:on-close="closePost"
:confirm-btn="null"
:cancel-btn="null"
>
<list-form :activeForm="'destroy'" @childForm="destroyEvent" />
</t-dialog>
</t-space>
</div>
</template>
<script setup>
import scarchBox from "@/components/scarchBox.vue";
import listForm from "./form/index.vue";
import { billType, billStatus } from "./codeValue/index";
import { ref, onMounted } from "vue";
import { MessagePlugin } from "tdesign-vue-next";
import { AddIcon, LoadIcon } from "tdesign-icons-vue-next";
import { useDestroy } from "@/stores/billDestroy";
//
const loading = ref(false);
const visiblePost = ref(false);
const destroyList = useDestroy();
const tableData = ref([]);
const data = ref([]);
const headerTitle = ref("审核");
const rowItem = ref({});
//
const columns = ref([
{
colKey: "serial-number",
title: "序号",
width: 50,
},
{
colKey: "billserial",
title: "票据编号",
align: "center",
width: "100",
},
{
colKey: "billType",
title: "票据类型",
align: "center",
width: "100",
cell: (h, { row }) => {
const type = billType.find((type) => type.value === row.billType);
return type ? type.label : "未知";
},
},
{
colKey: "breakNum",
title: "报损数量",
align: "center",
width: "100",
cell: (h, { row }) => {
return `${row.breakNum}`;
},
},
{
colKey: "breakDate",
title: "报损日期",
align: "center",
width: "100",
},
{
colKey: "operator",
title: "报损人员",
align: "center",
width: "100",
},
{
colKey: "breakInfo",
title: "报损原因",
ellipsis: true,
align: "center",
width: "100",
},
{
colKey: "status",
title: "操作",
width: 120,
align: "center",
fixed: "right",
},
]);
//
const tableList = async () => {
loading.value = true;
tableData.value = await destroyList.getDestroyList();
data.value = await destroyList.getDestroyList();
pagination.value.total = tableData.value.length;
const timerId = setTimeout(() => {
loading.value = false;
clearInterval(timerId);
}, 300);
};
//
const refresh = () => {
tableList();
};
//
const formData = ref({
billserial: "",
billType: "",
breakStatus: "",
breakDate: "",
});
//
const pagination = ref({
defaultCurrent: 1,
defaultPageSize: 10,
total: 50,
});
//
const resetting = () => {
formData.value = {
billserial: "",
billType: "",
breakStatus: "",
breakDate: "",
};
getNewTable();
};
//
const headerQuery = () => {
tableData.value = data.value;
if (
formData.value.billserial === "" &&
(formData.value.billType === undefined || formData.value.billType === "") &&
formData.value.breakDate === ""
) {
getNewTable();
} else {
const list = tableData.value.filter((item) => {
let arrList;
if (formData.value.billserial === item.billserial) {
arrList = item;
}
if (formData.value.billType === item.billType) {
arrList = item;
}
if (formData.value.breakDate === item.breakDate) {
arrList = item;
}
if (formData.value.billserial === "" && formData.value.billType === "" && formData.value.breakDate === "") {
arrList = item;
}
return arrList;
});
tableData.value = list;
pagination.value.total = list.length;
}
};
//
const breakageAdd = () => {
visiblePost.value = true;
};
//
const closePost = () => {
visiblePost.value = false;
};
//
const destroyEvent = async (data) => {
data = {
...rowItem.value.row,
breakStatus: Number(data.Status),
};
await destroyList.auditDestroyList(data);
getNewTable();
visiblePost.value = false;
MessagePlugin.success("提交成功");
};
//
const breakEdit = (item) => {
visiblePost.value = true;
rowItem.value = item;
};
//
const onReset = () => {};
// breakageList
const getNewTable = () => {
let arr = JSON.parse(localStorage.getItem("breakageList"));
if (arr) {
tableData.value = arr.destroyList;
data.value = arr.destroyList;
pagination.value.total = tableData.value.length;
}
if (arr === null) {
tableData.value = [];
pagination.value.total = tableData.value.length;
}
};
onMounted(() => {
getNewTable();
});
</script>
<style scoped lang="less">
.scarch-box {
width: 100%;
background-color: @base-white-color;
margin-bottom: 2rem;
.scarch-from {
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.table-box {
height: 42rem;
background-color: @base-white-color;
padding: 1rem;
padding-top: 0;
.table-header {
height: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
}
}
:deep(.t-form__controls-content) {
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,314 @@
<template>
<div class="back-color">
<t-layout style="height: 90%; background-color: #f5f7fb">
<t-header class="scarch-box">
<t-form
ref="form"
:data="formData"
label-width="calc(2em + 40px)"
layout="inline"
scroll-to-first-error="smooth"
class="scarch-from"
@reset="resetting"
@submit="headerQuery"
>
<scarch-box :btnNum="4" :colNum="8">
<template #scarchName>
<t-col :span="3">
<t-form-item label="票据编号:" name="billserial">
<t-input v-model="formData.billserial" class="form-item-content" maxlength="10"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="入库日期:" name="stockDate">
<t-date-picker v-model="formData.stockDate" class="form-item-content" clearable />
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="票据类型:" name="billType">
<t-select v-model="formData.billType" placeholder="请选择票据类型" class="form-item-content" clearable>
<t-option v-for="item in billType" :key="item.value" :value="item.value" :label="item.label"></t-option>
</t-select>
</t-form-item>
</t-col>
</template>
<template #scarchBtn>
<t-button theme="primary" type="submit">查询</t-button>
<t-button theme="default" type="reset">重置</t-button>
</template>
</scarch-box>
</t-form>
</t-header>
<t-content class="table-box">
<div class="table-header">
<div>
<h4 style="font-size: 110%">票据列表</h4>
</div>
<div>
<t-button shape="circle" theme="primary" @click="refresh" style="margin-left: 0.8rem">
<template #icon><load-icon /></template>
</t-button>
</div>
</div>
<t-base-table
hover
row-key="index"
:loading="loading"
:data="tableData"
:columns="columns"
:pagination="pagination"
class="table"
:max-height="550"
>
<template #status="slotProps">
<t-button theme="default" variant="text" size="small" @click="exportPdf(slotProps)">导出pdf</t-button>
</template>
</t-base-table>
</t-content>
</t-layout>
</div>
</template>
<script setup>
import scarchBox from "@/components/scarchBox.vue";
import { billType } from "./codeValue/index";
import { ref, onMounted } from "vue";
import { MessagePlugin } from "tdesign-vue-next";
import { LoadIcon } from "tdesign-icons-vue-next";
import { useStock } from "@/stores/billStock";
import { exportToPDF } from "@/utils/pdf";
//
const loading = ref(false);
const stockList = useStock();
const tableData = ref();
const data = ref();
//
const columns = ref([
{
colKey: "serial-number",
title: "序号",
width: 50,
},
{
colKey: "billserial",
title: "票据编号",
align: "center",
width: "100",
},
{
colKey: "billType",
title: "票据类型",
align: "center",
width: "100",
cell: (h, { row }) => {
const type = billType.find((type) => type.value === row.billType);
return type ? type.label : "未知";
},
},
{
colKey: "stockNum",
title: "入库数量",
align: "center",
width: "100",
cell: (h, { row }) => {
return `${row.stockNum}`;
},
},
{
colKey: "stockDate",
title: "入库日期",
align: "center",
width: "100",
},
{
colKey: "operator",
title: "操作员",
align: "center",
width: "100",
},
{
colKey: "remark",
title: "备注",
align: "center",
width: "100",
},
{
colKey: "status",
title: "操作",
width: 120,
align: "center",
fixed: "right",
},
]);
//
const tableList = async () => {
loading.value = true;
tableData.value = await stockList.getStockList();
data.value = await stockList.getStockList();
pagination.value.total = tableData.value.length;
const timerId = setTimeout(() => {
loading.value = false;
clearInterval(timerId);
}, 300);
};
//
const refresh = () => {
tableList();
};
//
const formData = ref({
billserial: "",
billType: "",
stockDate: "",
});
//
const pagination = ref({
defaultCurrent: 1,
defaultPageSize: 10,
total: 50,
});
//
const resetting = () => {
formData.value = {
billserial: "",
billType: "",
stockDate: "",
};
getNewTable();
};
//
const headerQuery = () => {
tableData.value = data.value;
if (
formData.value.billserial === "" &&
(formData.value.billType === undefined || formData.value.billType === "") &&
formData.value.stockDate === ""
) {
getNewTable();
} else {
const list = tableData.value.filter((item) => {
let arrList;
if (formData.value.billserial === item.billserial) {
arrList = item;
}
if (formData.value.billType === item.billType) {
arrList = item;
}
if (formData.value.stockDate === item.stockDate) {
arrList = item;
}
if (formData.value.billserial === "" && formData.value.billType === "" && formData.value.stockDate === "") {
arrList = item;
}
return arrList;
});
tableData.value = list;
pagination.value.total = list.length;
}
};
// menuManagement
const getNewTable = () => {
let arr = JSON.parse(localStorage.getItem("menuManagement"));
if (arr) {
tableData.value = arr.stockList;
data.value = arr.stockList;
pagination.value.total = tableData.value.length;
} else {
tableList();
}
};
// pdf
const exportPdf = (slotProps) => {
// const content = slotProps.row;
const content = [
//
{
text: "票据标题",
style: "header",
alignment: "center",
margin: [0, 0, 0, 0],
},
//
{
columns: [
{ text: "发票编号:", style: "label", alignment: "right" },
{ text: "1234567890", style: "value" },
{ text: "日期:", style: "label", alignment: "right" },
{ text: "2023-04-05", style: "value" },
],
margin: [0, 20, 0, 0],
},
//
{
table: {
widths: ["*", "auto", "*"],
body: [
[
{ text: "商品名称", style: "tableHeader" },
{ text: "数量", style: "tableHeader" },
{ text: "单价", style: "tableHeader" },
],
["商品A", "10件", "$10.00"],
["商品B", "5件", "$20.00"],
// [{ text: "", colSpan: 2, alignment: "right" }, "$150.00"],
],
},
layout: "noBorders",
margin: [0, 20, 0, 0],
},
//
{
text: "本票据一式两份,甲乙双方各执一份,具有同等法律效力。",
style: "footer",
alignment: "center",
margin: [0, 0, 0, 30],
},
];
exportToPDF(content);
};
onMounted(() => {
getNewTable();
});
</script>
<style scoped lang="less">
.scarch-box {
width: 100%;
background-color: @base-white-color;
margin-bottom: 2rem;
.scarch-from {
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.table-box {
height: 42rem;
background-color: @base-white-color;
padding: 1rem;
padding-top: 0;
.table-header {
height: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
}
}
:deep(.t-form__controls-content) {
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,310 @@
<template>
<div class="back-color" style="overflow-y: hidden">
<t-layout style="height: 100%; background-color: #f5f7fb">
<t-aside class="asideTree">
<t-space direction="vertical">
<t-tree
:data="personName"
hover
transition
activable
expandAll
:expand-mutex="mutex"
expand-on-click-node="true"
@click="onClick"
/>
</t-space>
</t-aside>
<t-content>
<t-layout style="height: 100%; background-color: #f5f7fb" v-if="pageJudge">
<t-header class="scarch-box">
<t-form
ref="form"
:data="scarchData"
label-width="calc(2em + 40px)"
layout="inline"
scroll-to-first-error="smooth"
class="scarch-from"
@reset="resetting"
@submit="headerQuery"
>
<scarch-box :btnNum="2" :colNum="10">
<template #scarchName>
<t-col :span="3">
<t-form-item label="票据编号:" name="billserial">
<t-input class="form-item-content" v-model="scarchData.billserial" maxlength="10"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="领用时间:" name="quitneckDate">
<t-date-picker class="form-item-content" v-model="scarchData.quitneckDate" clearable />
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="票据类型:" name="billType" style="margin-bottom: 0.3rem">
<t-select class="form-item-content" v-model="scarchData.billType" placeholder="请选择票据类型" clearable>
<t-option v-for="item in billType" :key="item.value" :value="item.value" :label="item.label"></t-option>
</t-select>
</t-form-item>
</t-col>
</template>
<template #scarchBtn>
<t-button theme="primary" type="submit">查询</t-button>
<t-button theme="default" type="reset">重置</t-button>
</template>
</scarch-box>
</t-form>
</t-header>
<t-content class="table-box">
<div class="table-header">
<div>
<h4 style="font-size: 110%">票据退领列表</h4>
</div>
<div>
<t-button shape="circle" theme="primary" @click="refresh" style="margin-left: 0.8rem">
<template #icon><load-icon /></template>
</t-button>
</div>
</div>
<t-base-table
hover
row-key="index"
:loading="loading"
:data="tableData"
:columns="columns"
:pagination="pagination"
class="table"
:max-height="550"
/>
</t-content>
</t-layout>
<t-layout class="layoutPage" v-else>
<span> 请点击左侧员工名单 </span>
</t-layout>
</t-content>
</t-layout>
</div>
</template>
<script setup>
import scarchBox from "@/components/scarchBox.vue";
import { billType } from "./codeValue/index.js";
import { ref, onMounted, nextTick } from "vue";
import { MessagePlugin } from "tdesign-vue-next";
import { LoadIcon } from "tdesign-icons-vue-next";
import { useQuitneckList } from "@/stores/billQuitneck";
import { useReceiptList } from "@/stores/billReceipt";
const quitneckList = useQuitneckList();
const receiptList = useReceiptList();
const personName = ref([]);
const tableData = ref([]);
const data = ref([]);
const rowItem = ref({});
const loading = ref(false);
const pageJudge = ref(false);
const columns = ref([
{
colKey: "serial-number",
title: "序号",
width: 50,
},
{
colKey: "billserial",
title: "票据编号",
align: "center",
width: 100,
},
{
colKey: "proposer",
title: "申请人",
align: "center",
width: 100,
},
{
colKey: "billType",
title: "票据类型",
align: "center",
width: 100,
cell: (h, { row }) => {
const type = billType.find((type) => type.value === row.billType);
return type ? type.label : "未知";
},
},
{
colKey: "quitneckNum",
title: "退领数量",
align: "center",
width: 100,
cell: (h, { row }) => {
return `${row.quitneckNum}`;
},
},
{
colKey: "quitneckDate",
title: "退领时间",
align: "center",
width: 100,
},
{
colKey: "quitneckReason",
title: "退领原因",
ellipsis: true,
align: "center",
width: 200,
},
]);
//
const scarchData = ref({});
//
const pagination = ref({
defaultCurrent: 1,
defaultPageSize: 10,
total: 50,
});
//
const personList = async () => {
personName.value = await receiptList.getPersonNameList();
};
//
const headerQuery = () => {
tableData.value = data.value;
console.log(scarchData.value.billserial, scarchData.value.billType, scarchData.value.quitneckDate);
if (
scarchData.value.billserial === "" &&
(scarchData.value.billType === undefined || scarchData.value.billType === "") &&
(scarchData.value.quitneckDate === undefined || scarchData.value.quitneckDate === "")
) {
tableData.value = data.value;
pagination.value.total = tableData.value.length;
} else {
const list = tableData.value.filter((item) => {
let arrList;
if (scarchData.value.billserial === item.billserial) {
arrList = item;
}
if (scarchData.value.billType === item.billType) {
arrList = item;
}
if (scarchData.value.quitneckDate === item.quitneckDate) {
arrList = item;
}
if (scarchData.value.billserial === "" && scarchData.value.billType === "" && scarchData.value.quitneckDate === "") {
arrList = item;
}
console.log(arrList);
return arrList;
});
tableData.value = list;
pagination.value.total = list.length;
}
};
//
const resetting = () => {
scarchData.value = {
billserial: "",
billType: "",
quitneckDate: "",
};
tableData.value = data.value;
pagination.value.total = tableData.value.length;
};
//
const Quitneck = (value) => {
dialogData.value = {
quitneckDate: "",
quitneckReason: "",
quitneckNum: "",
};
visiblePost.value = true;
rowItem.value = value;
};
const onClick = async (context) => {
//
if (context.node.value === "t1") {
return;
}
pageJudge.value = true;
loading.value = true;
//
tableData.value = await quitneckList.getQuitneckList(context.node.label);
data.value = await quitneckList.getQuitneckList(context.node.label);
pagination.value.total = tableData.value.length;
const timerId = setTimeout(() => {
loading.value = false;
clearInterval(timerId);
}, 300);
};
// //
// const refresh = () => {
// getTableData();
// pagination.value.total = tableData.value.length;
// };
// ReceiptList
const getPersonName = () => {
let arr = JSON.parse(localStorage.getItem("ReceiptList"));
if (arr) {
personName.value = arr.personName;
} else {
personList();
}
};
onMounted(async () => {
getPersonName();
});
</script>
<style scoped lang="less">
.asideTree {
margin-right: 2rem;
display: flex;
justify-content: center;
padding: 1rem;
}
.scarch-box {
width: 100%;
background-color: @base-white-color;
margin-bottom: 2rem;
.scarch-from {
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.table-box {
height: 41rem;
background-color: @base-white-color;
padding: 1rem;
padding-top: 0;
.table-header {
height: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.layoutPage {
height: 100%;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
span {
font-size: 20px;
font-weight: 800;
color: #191919;
}
}
:deep(.t-tree--transition .t-tree__label) {
width: 10rem;
}
:deep(.t-form__controls-content) {
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,364 @@
<template>
<div class="back-color" style="overflow-y: hidden">
<t-layout style="height: 100%; background-color: #f5f7fb">
<t-aside class="asideTree">
<t-space direction="vertical">
<t-tree
:data="personName"
hover
transition
activable
expandAll
:expand-mutex="mutex"
expand-on-click-node="true"
@click="onClick"
/>
</t-space>
</t-aside>
<t-content>
<t-layout style="height: 100%; background-color: #f5f7fb">
<t-header class="scarch-box">
<t-form
ref="form"
:data="scarchData"
label-width="calc(2em + 40px)"
layout="inline"
scroll-to-first-error="smooth"
class="scarch-from"
@reset="resetting"
@submit="headerQuery"
>
<scarch-box :btnNum="2" :colNum="10">
<template #scarchName>
<t-col :span="3">
<t-form-item label="票据编号:" name="billserial">
<t-input class="form-item-content" v-model="scarchData.billserial" maxlength="10"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="领用时间:" name="receiptDate">
<t-date-picker class="form-item-content" v-model="scarchData.receiptDate" clearable />
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="票据类型:" name="billType" style="margin-bottom: 0.3rem">
<t-select class="form-item-content" v-model="scarchData.billType" placeholder="请选择票据类型" clearable>
<t-option v-for="item in billType" :key="item.value" :value="item.value" :label="item.label"></t-option>
</t-select>
</t-form-item>
</t-col>
</template>
<template #scarchBtn>
<t-button theme="primary" type="submit">查询</t-button>
<t-button theme="default" type="reset">重置</t-button>
</template>
</scarch-box>
</t-form>
</t-header>
<t-content class="table-box">
<div class="table-header">
<div>
<h4 style="font-size: 110%">票据领用列表</h4>
</div>
<div>
<t-button shape="circle" theme="primary" @click="refresh" style="margin-left: 0.8rem">
<template #icon><load-icon /></template>
</t-button>
</div>
</div>
<t-base-table
hover
row-key="index"
:loading="loading"
:data="tableData"
:columns="columns"
:pagination="pagination"
class="table"
:max-height="550"
>
<template #status="slotProps">
<t-button
theme="default"
variant="text"
size="small"
@click="Quitneck(slotProps)"
:disabled="slotProps.row.receiptNum === 0"
>退领</t-button
>
</template>
</t-base-table>
</t-content>
</t-layout>
</t-content>
</t-layout>
<t-space>
<t-dialog
ref="postForm"
v-model:visible="visiblePost"
header="退领"
width="40%"
:confirm-on-enter="true"
:on-close="closePost"
:confirm-btn="null"
:cancel-btn="null"
>
<list-form :activeForm="'receipt'" @childForm="receiptromEvent" />
</t-dialog>
</t-space>
</div>
</template>
<script setup>
import scarchBox from "@/components/scarchBox.vue";
import listForm from "./form/index.vue";
import { billType } from "./codeValue/index";
import { ref, onMounted, nextTick } from "vue";
import { MessagePlugin } from "tdesign-vue-next";
import { LoadIcon } from "tdesign-icons-vue-next";
import { useReceiptList } from "@/stores/billReceipt";
const receiptList = useReceiptList();
const personName = ref([]);
const tableData = ref([]);
const data = ref([]);
const loading = ref(false);
const visiblePost = ref(false);
const rowItem = ref({});
const columns = ref([
{
colKey: "serial-number",
title: "序号",
width: 50,
},
{
colKey: "billserial",
title: "票据编号",
align: "center",
width: 100,
},
{
colKey: "proposer",
title: "申请人",
align: "center",
width: 100,
},
{
colKey: "billType",
title: "票据类型",
align: "center",
width: 100,
cell: (h, { row }) => {
const type = billType.find((type) => type.value === row.billType);
return type ? type.label : "未知";
},
},
{
colKey: "receiptNum",
title: "领用数量",
align: "center",
width: 100,
cell: (h, { row }) => {
return `${row.receiptNum}`;
},
},
{
colKey: "receiptDate",
title: "领用时间",
align: "center",
width: 100,
},
{
colKey: "useInfo",
title: "用途",
ellipsis: true,
align: "center",
width: 200,
},
{
colKey: "status",
title: "操作",
width: 120,
align: "center",
fixed: "right",
},
]);
//
const scarchData = ref({
billserial: "",
});
//
const pagination = ref({
defaultCurrent: 1,
defaultPageSize: 10,
total: 50,
});
//
const personList = async () => {
personName.value = await receiptList.getPersonNameList();
};
//
const headerQuery = () => {
tableData.value = data.value;
if (
scarchData.value.billserial === "" &&
(scarchData.value.billType === undefined || scarchData.value.billType === "") &&
(scarchData.value.receiptDate === undefined || scarchData.value.receiptDate === "")
) {
getNewTable();
} else {
const list = tableData.value.filter((item) => {
let arrList;
if (scarchData.value.billserial === item.billserial) {
arrList = item;
}
if (scarchData.value.billType === item.billType) {
arrList = item;
}
if (scarchData.value.receiptDate === item.receiptDate) {
arrList = item;
}
if (scarchData.value.billserial === "" && scarchData.value.billType === "" && scarchData.value.receiptDate === "") {
arrList = item;
}
return arrList;
});
tableData.value = list;
pagination.value.total = list.length;
}
};
//
const resetting = () => {
scarchData.value = {
billserial: "",
billType: "",
receiptDate: "",
};
getNewTable();
};
// 退
const Quitneck = (value) => {
visiblePost.value = true;
rowItem.value = value;
};
const receiptromEvent = async (data) => {
if (rowItem.value.row.receiptNum - data.quitneckNum < 0) {
return MessagePlugin.error("退领数量不能大于领用数量");
}
data.id = rowItem.value.row.id;
data.billserial = rowItem.value.row.billserial;
data.billType = rowItem.value.row.billType;
data.proposer = rowItem.value.row.proposer;
await receiptList.getquitneckNum(data);
getTableData();
MessagePlugin.success("提交成功");
visiblePost.value = false;
};
const onClick = async (context) => {
//
if (context.node.value === "t1") {
return;
}
loading.value = true;
//
tableData.value = await receiptList.getReceiptList({
name: context.node.label,
});
data.value = await receiptList.getReceiptList({
name: context.node.label,
});
pagination.value.total = tableData.value.length;
const timerId = setTimeout(() => {
loading.value = false;
clearInterval(timerId);
}, 300);
};
//
const refresh = () => {
getTableData();
};
// menuManagement
const getPersonName = async () => {
let arr = JSON.parse(localStorage.getItem("ReceiptList"));
if (arr) {
personName.value = arr.personName;
} else {
await personList();
getTableData();
}
};
// menuManagement
const getTableData = async () => {
let arr = JSON.parse(localStorage.getItem("ReceiptList"));
if (arr.receiptList.length > 0) {
loading.value = true;
tableData.value = arr.receiptList;
pagination.value.total = tableData.value.length;
const timerId = setTimeout(() => {
loading.value = false;
clearInterval(timerId);
}, 300);
} else {
await nextTick();
//
const firstNodeWithChildren = personName.value.find((node) => Array.isArray(node.children) && node.children.length > 0);
if (firstNodeWithChildren) {
const simulatedContext = {
node: {
label: "孙东宇",
},
};
onClick(simulatedContext);
}
}
};
onMounted(async () => {
await getPersonName();
await getTableData();
});
</script>
<style scoped lang="less">
.asideTree {
margin-right: 2rem;
display: flex;
justify-content: center;
padding: 1rem;
}
.scarch-box {
width: 100%;
background-color: @base-white-color;
margin-bottom: 2rem;
.scarch-from {
width: 100%;
height: 60px;
display: flex;
align-items: center;
}
}
.table-box {
height: 41rem;
background-color: @base-white-color;
padding: 1rem;
padding-top: 0;
.table-header {
height: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
}
}
:deep(.t-tree--transition .t-tree__label) {
width: 10rem;
}
:deep(.t-form__controls-content) {
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,318 @@
<template>
<div class="back-color">
<t-layout style="height: 90%; background-color: #f5f7fb">
<t-header class="scarch-box">
<t-form
ref="form"
:data="formData"
label-width="calc(2em + 40px)"
layout="inline"
scroll-to-first-error="smooth"
class="scarch-from"
@reset="resetting"
@submit="headerQuery"
>
<scarch-box :btnNum="4" :colNum="8">
<template #scarchName>
<t-col :span="3">
<t-form-item label="票据编号:" name="billserial">
<t-input v-model="formData.billserial" class="form-item-content" maxlength="10"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="入库日期:" name="stockDate">
<t-date-picker v-model="formData.stockDate" class="form-item-content" clearable />
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="票据类型:" name="billType">
<t-select v-model="formData.billType" placeholder="请选择票据类型" class="form-item-content" clearable>
<t-option v-for="item in billType" :key="item.value" :value="item.value" :label="item.label"></t-option>
</t-select>
</t-form-item>
</t-col>
</template>
<template #scarchBtn>
<t-button theme="primary" type="submit">查询</t-button>
<t-button theme="default" type="reset">重置</t-button>
</template>
</scarch-box>
</t-form>
</t-header>
<t-content class="table-box">
<div class="table-header">
<div>
<h4 style="font-size: 110%">票据入库列表</h4>
</div>
<div>
<t-button theme="primary" size="small" @click="addStock">
<template #icon><add-icon /></template>
新增票据
</t-button>
<t-button shape="circle" theme="primary" @click="refresh" style="margin-left: 0.8rem">
<template #icon><load-icon /></template>
</t-button>
</div>
</div>
<t-base-table
hover
row-key="index"
:loading="loading"
:data="tableData"
:columns="columns"
:pagination="pagination"
class="table"
:max-height="550"
>
<template #status="slotProps">
<t-button theme="default" variant="text" size="small" @click="stockEdit(slotProps)">修改</t-button>
<t-popconfirm content="确认删除吗" @confirm="stockDelete(slotProps)">
<t-button theme="default" variant="text" size="small">删除</t-button>
</t-popconfirm>
</template>
</t-base-table>
</t-content>
</t-layout>
<t-space>
<t-dialog
ref="postForm"
v-model:visible="visiblePost"
header="新增票据"
width="40%"
:confirm-on-enter="true"
:on-close="closePost"
:confirm-btn="null"
:cancel-btn="null"
>
<list-form :activeForm="'stock'" @childForm="stockromEvent" :editFrom="editFrom" />
</t-dialog>
</t-space>
</div>
</template>
<script setup>
import scarchBox from "@/components/scarchBox.vue";
import listForm from "./form/index.vue";
import { ref, onMounted } from "vue";
import { MessagePlugin } from "tdesign-vue-next";
import { AddIcon, LoadIcon } from "tdesign-icons-vue-next";
import { useStock } from "@/stores/billStock";
import { billType } from "./codeValue/index";
//
const loading = ref(false);
const visiblePost = ref(false);
const stockList = useStock();
const tableData = ref();
const editFrom = ref();
const data = ref();
//
const columns = ref([
{
colKey: "serial-number",
title: "序号",
width: 50,
},
{
colKey: "billserial",
title: "票据编号",
align: "center",
width: "100",
},
{
colKey: "billType",
title: "票据类型",
align: "center",
width: "100",
cell: (h, { row }) => {
const type = billType.find((type) => type.value === row.billType);
return type ? type.label : "未知";
},
},
{
colKey: "stockNum",
title: "入库数量",
align: "center",
width: "100",
cell: (h, { row }) => {
return `${row.stockNum}`;
},
},
{
colKey: "stockDate",
title: "入库日期",
align: "center",
width: "100",
},
{
colKey: "operator",
title: "操作员",
align: "center",
width: "100",
},
{
colKey: "remark",
title: "备注",
align: "center",
width: "100",
},
{
colKey: "status",
title: "操作",
width: 120,
align: "center",
fixed: "right",
},
]);
//
const tableList = async () => {
loading.value = true;
tableData.value = await stockList.getStockList();
data.value = await stockList.getStockList();
pagination.value.total = tableData.value.length;
const timerId = setTimeout(() => {
loading.value = false;
clearInterval(timerId);
}, 300);
};
//
const refresh = () => {
tableList();
};
//
const formData = ref({
billserial: "",
billType: "",
stockDate: "",
});
//
const pagination = ref({
defaultCurrent: 1,
defaultPageSize: 10,
total: 50,
});
//
const resetting = () => {
formData.value = {
billserial: "",
billType: "",
stockDate: "",
};
getNewTable();
};
//
const headerQuery = () => {
tableData.value = data.value;
if (
formData.value.billserial === "" &&
(formData.value.billType === undefined || formData.value.billType === "") &&
formData.value.stockDate === ""
) {
getNewTable();
} else {
const list = tableData.value.filter((item) => {
let arrList;
if (formData.value.billserial === item.billserial) {
arrList = item;
}
if (formData.value.billType === item.billType) {
arrList = item;
}
if (formData.value.stockDate === item.stockDate) {
arrList = item;
}
if (formData.value.billserial === "" && formData.value.billType === "" && formData.value.stockDate === "") {
arrList = item;
}
return arrList;
});
tableData.value = list;
// @ts-expect-error
pagination.value.total = list.length;
}
};
//
const addStock = () => {
visiblePost.value = true;
};
const stockromEvent = async (data) => {
await stockList.addStockList(data);
getNewTable();
MessagePlugin.success("提交成功");
visiblePost.value = false;
};
//
const closePost = () => {
visiblePost.value = false;
};
//
const stockEdit = (item) => {
visiblePost.value = true;
tableData.value.forEach((itemTable) => {
if (itemTable.id === item.row.id) {
editFrom.value = itemTable;
}
});
};
//
const stockDelete = async (itme) => {
await stockList.deleteStockList(itme.row);
getNewTable();
};
// menuManagement
const getNewTable = () => {
let arr = JSON.parse(localStorage.getItem("menuManagement"));
if (arr) {
tableData.value = arr.stockList;
data.value = arr.stockList;
pagination.value.total = tableData.value.length;
} else {
tableList();
}
};
onMounted(() => {
getNewTable();
});
</script>
<style scoped lang="less">
.scarch-box {
width: 100%;
background-color: @base-white-color;
margin-bottom: 2rem;
.scarch-from {
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.table-box {
height: 42rem;
background-color: @base-white-color;
padding: 1rem;
padding-top: 0;
.table-header {
height: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
}
}
:deep(.t-form__controls-content) {
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,22 @@
// 票据类型
export const billType = [
{ label: "票据类型1", value: 0 },
{ label: "票据类型2", value: 1 },
{ label: "票据类型3", value: 2 },
{ label: "票据类型4", value: 3 },
{ label: "票据类型5", value: 4 },
];
// 状态
export const billStatus = [
{ label: "审核中", value: 0 },
{ label: "审核通过", value: 1 },
{ label: "审核拒绝", value: 2 },
];
// 审批状态
export const exaStatus = [
{ label: "待审批", value: 0 },
{ label: "审核中", value: 1 },
{ label: "审核通过", value: 2 },
{ label: "审核拒绝", value: 3 },
];

View File

@ -0,0 +1,13 @@
<template>
<div>
<div class="double-box">double-box</div>
</div>
</template>
<style scoped lang="less">
.double-box {
width: 186px;
height: 180px;
background-color: rgb(8, 48, 139);
}
</style>

View File

@ -0,0 +1,13 @@
<template>
<div>
<div class="little-box">little-box</div>
</div>
</template>
<style scoped lang="less">
.little-box {
width: 75px;
height: 75px;
background-color: greenyellow;
}
</style>

View File

@ -0,0 +1,233 @@
<template>
<div class="back-color">
<t-layout style="height: 90%; background-color: #f5f7fb">
<t-header class="scarch-box">
<t-form
ref="form"
:data="scarchData"
label-width="calc(2em + 40px)"
layout="inline"
scroll-to-first-error="smooth"
class="scarch-from"
@reset="resetting"
@submit="headerQuery"
>
<scarch-box :btnNum="4" :colNum="8">
<template #scarchName>
<t-col :span="3" style="padding-left: 0">
<t-form-item label="部门:" name="branch">
<t-input v-model="scarchData.branch" class="form-item-content"></t-input>
</t-form-item>
</t-col>
</template>
<template #scarchBtn>
<t-button theme="primary" type="submit">查询</t-button>
<t-button theme="default" type="reset">重置</t-button>
</template>
</scarch-box>
</t-form>
</t-header>
<t-content class="table-box">
<div class="table-header">
<div>
<h4 style="font-size: 110%">报表明细</h4>
</div>
<div>
<t-button theme="primary" size="small" @click="exportExcel"> 导出报表明细 </t-button>
<t-button shape="circle" theme="primary" @click="refresh" style="margin-left: 0.8rem">
<template #icon><load-icon /></template>
</t-button>
</div>
</div>
<t-base-table
hover
row-key="index"
:loading="loading"
:data="tableData"
:columns="columns"
:pagination="pagination"
class="table"
:max-height="550"
>
</t-base-table>
</t-content>
</t-layout>
</div>
</template>
<script setup>
import scarchBox from "@/components/scarchBox.vue";
import { ref, onMounted } from "vue";
import { MessagePlugin } from "tdesign-vue-next";
import { LoadIcon } from "tdesign-icons-vue-next";
import { reqDetailReportList } from "@/api/finance-bill-manage/detailReportList";
import { ExcelUtils } from "@/utils/excel";
const tableData = ref([]);
const dataList = ref([]);
const loading = ref(false);
const columns = ref([
{
colKey: "serial-number",
title: "序号",
width: 50,
},
{
colKey: "branch",
title: "部门",
align: "center",
width: 100,
},
{
colKey: "stockNum",
title: "入库量",
align: "center",
width: 100,
},
{
colKey: "cancelNum",
title: "退库量",
align: "center",
width: 100,
},
{
colKey: "receiveNum",
title: "领用量",
align: "center",
width: 100,
},
{
colKey: "breakNum",
title: "报损量",
align: "center",
width: 100,
},
{
colKey: "destoryNum",
title: "核销量",
align: "center",
width: 100,
},
{
colKey: "grossBillRatio",
title: "总票据比例",
ellipsis: true,
align: "center",
width: 100,
},
]);
//
const scarchData = ref({});
//
const pagination = ref({
defaultCurrent: 1,
defaultPageSize: 10,
total: 50,
});
//
const tableList = async () => {
loading.value = true;
const { data } = await reqDetailReportList();
tableData.value = data.list;
dataList.value = data.list;
pagination.value.total = tableData.value.length;
const timerId = setTimeout(() => {
loading.value = false;
clearInterval(timerId);
}, 300);
};
//
const headerQuery = () => {
tableData.value = dataList.value;
if (scarchData.value.branch === "") {
tableData.value = data.value;
pagination.value.total = tableData.value.length;
} else {
const list = tableData.value.filter((item) => {
let arrList;
if (scarchData.value.branch === item.branch) {
arrList = item;
}
return arrList;
});
tableData.value = list;
pagination.value.total = list.length;
}
};
//
const resetting = () => {
scarchData.value = {
branch: "",
};
tableData.value = dataList.value;
pagination.value.total = tableData.value.length;
};
//
const refresh = () => {
tableList();
};
// excel
const exportExcel = () => {
const title = "报表明细excel";
const titleFile = "报表明细";
const columns = [
{ header: "部门", key: "1", width: 20 },
{ header: "入库量", key: "2", width: 20 },
{ header: "退库量", key: "3", width: 20 },
{ header: "领用量", key: "4", width: 20 },
{ header: "报损量", key: "5", width: 20 },
{ header: "核销量", key: "6", width: 20 },
{ header: "总票据比例", key: "7", width: 20 },
];
const addRow = [];
tableData.value.forEach((item) => {
addRow.push({
1: item.branch,
2: item.stockNum,
3: item.cancelNum,
4: item.receiveNum,
5: item.breakNum,
6: item.destoryNum,
7: item.grossBillRatio,
});
});
ExcelUtils(title, titleFile, columns, addRow);
};
onMounted(() => {
tableList();
});
</script>
<style scoped lang="less">
.scarch-box {
width: 100%;
background-color: @base-white-color;
margin-bottom: 2rem;
.scarch-from {
width: 100%;
height: 60px;
display: flex;
align-items: center;
}
}
.table-box {
height: 41rem;
background-color: @base-white-color;
padding: 1rem;
padding-top: 0;
.table-header {
height: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
}
}
:deep(.t-form__controls-content) {
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,81 @@
<template>
<div class="grid">
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<TextVue class="grid-div grid-item-lm" />
<DoubleBox class="grid-double grid-item-lm" />
<DoubleBox class="grid-double grid-item-lm" />
<DoubleBox class="grid-double grid-item-lm" />
<DoubleBox class="grid-double grid-item-lm" />
<DoubleBox class="grid-double grid-item-lm" />
<DoubleBox class="grid-double grid-item-lm" />
<!-- <DoubleBox class="grid-double grid-item-lm" /> -->
</div>
</template>
<script setup>
import { onMounted } from "vue";
import Sortable from "sortablejs";
import TextVue from "./components/TextVue.vue";
import DoubleBox from "./components/DoubleBox.vue";
//使onMountedquerySelectorgriddivgridnull
onMounted(() => {
const grid = document.querySelector(".grid");
//sortable
new Sortable(grid, {
animation: 150,
handle: ".grid-item-lm", //grid.grid-item
});
});
</script>
<style scoped>
.grid {
padding: 20px 10%;
display: grid;
justify-content: center;
align-items: center;
/* 声明列的高度 */
grid-template-columns: repeat(auto-fill, 75px);
/* 声明行的高度 */
grid-template-rows: repeat(auto-fill, 75px);
/* 声明行间距和列间距 */
grid-gap: 36px;
}
.grid-div {
/* 声明宽占4个小盒子 */
grid-column: span 1;
/* 声明高占2个小盒子 */
grid-row: span 1;
}
.grid-double {
grid-column: span 2;
grid-row: span 2;
}
</style>

View File

@ -0,0 +1,344 @@
<template>
<div>
<t-space direction="vertical" style="width: 100%" v-if="props.activeForm === 'stock'">
<div>
<t-form
ref="formDialog"
scroll-to-first-error="smooth"
label-align="left"
:rules="FORM_RULES_STOCK"
:data="stockData"
:colon="true"
@submit="stockAdd"
label-width="calc(2em + 55px)"
layout="inline"
@reset="onReset"
>
<t-form-item label="票据编号" name="billserial" :span="10" style="margin-bottom: 0.5rem">
<t-input v-model="stockData.billserial" placeholder="请输入票据编号" maxlength="10"></t-input>
</t-form-item>
<t-form-item label="票据类型" name="billType" :span="12" style="width: 16rem; margin-bottom: 0.5rem">
<t-select v-model="stockData.billType" clearable placeholder="请选择票据类型">
<t-option v-for="item in billType" :key="item.value" :label="item.label" :value="item.value" />
</t-select>
</t-form-item>
<t-form-item label="入库数量" name="stockNum" :span="12" style="margin-bottom: 0.5rem">
<t-input type="number" v-model="stockData.stockNum" placeholder="请输入入库数量"></t-input>
</t-form-item>
<t-form-item label="入库时间" name="stockDate" :span="10" style="width: 16rem; margin-bottom: 0.5rem">
<t-date-picker v-model="stockData.stockDate" placeholder="请选择入库时间" clearable />
</t-form-item>
<t-form-item label="操作员" name="operator" :span="10" style="margin-bottom: 0.5rem">
<t-input v-model="stockData.operator" placeholder="请输入操作员"></t-input>
</t-form-item>
<t-form-item label="备注" name="remark" style="width: 33.6rem">
<t-textarea v-model="stockData.remark" placeholder="请输入备注"></t-textarea>
</t-form-item>
<t-form-item>
<t-space size="small">
<t-button theme="primary" type="submit">提交</t-button>
<t-button theme="default" variant="base" type="reset">重置</t-button>
</t-space>
</t-form-item>
</t-form>
</div>
</t-space>
<t-space direction="vertical" v-if="props.activeForm === 'cancel'">
<div>
<t-form
ref="formDialog"
scroll-to-first-error="smooth"
label-align="left"
:rules="FORM_RULES_CANCEL"
:data="cancelData"
:colon="true"
@submit="cancelAdd"
label-width="calc(2em + 55px)"
@reset="onReset"
>
<t-form-item label="审批人" name="approver" style="margin-bottom: 1.5rem; width: 35rem">
<t-input v-model="cancelData.approver" placeholder="请输入审批人"></t-input>
</t-form-item>
<t-form-item label="审批时间" name="approvalDate" style="margin-bottom: 1.5rem; width: 35rem">
<t-date-picker v-model="cancelData.approvalDate" placeholder="请选择审批时间" clearable style="width: 35rem" />
</t-form-item>
<t-form-item label="审批原因" name="approvalReason">
<t-textarea v-model="cancelData.approvalReason" placeholder="请输入审批原因"></t-textarea>
</t-form-item>
<t-form-item>
<t-space size="small">
<t-button theme="primary" type="submit">提交</t-button>
<t-button theme="default" variant="base" type="reset">重置</t-button>
</t-space>
</t-form-item>
</t-form>
</div>
</t-space>
<t-space direction="vertical" v-if="props.activeForm === 'receipt'">
<div>
<t-form
ref="formDialog"
scroll-to-first-error="smooth"
label-align="left"
:rules="FORM_RULES_RECEIPT"
:data="receiptData"
:colon="true"
@submit="quitneckAdd"
label-width="calc(2em + 55px)"
@reset="onReset"
>
<t-form-item label="退领张数" name="quitneckNum" style="margin-bottom: 1.5rem; width: 35rem">
<t-input v-model="receiptData.quitneckNum" type="number" placeholder="请输入退领张数"></t-input>
</t-form-item>
<t-form-item label="退领时间" name="quitneckDate" style="margin-bottom: 1.5rem; width: 35rem">
<t-date-picker v-model="receiptData.quitneckDate" placeholder="请选择退领时间" clearable style="width: 35rem" />
</t-form-item>
<t-form-item label="退领原因" name="quitneckReason">
<t-textarea v-model="receiptData.quitneckReason" placeholder="请输入退领原因"></t-textarea>
</t-form-item>
<t-form-item>
<t-space size="small">
<t-button theme="primary" type="submit">提交</t-button>
<t-button theme="default" variant="base" type="reset">重置</t-button>
</t-space>
</t-form-item>
</t-form>
</div>
</t-space>
<t-space direction="vertical" v-if="props.activeForm === 'break'" style="width: 100%">
<div>
<t-form
ref="formDialog"
scroll-to-first-error="smooth"
label-align="left"
:rules="FORM_RULES_BREAK"
:data="breakData"
:colon="true"
@submit="breakSub"
label-width="calc(2em + 55px)"
layout="inline"
@reset="onReset"
>
<t-form-item label="票据编号" name="billserial" :span="10" style="margin-bottom: 0.5rem">
<t-input v-model="breakData.billserial" placeholder="请输入票据编号" maxlength="10"></t-input>
</t-form-item>
<t-form-item label="操作员" name="operator" :span="10" style="margin-bottom: 0.5rem">
<t-input v-model="breakData.operator" placeholder="请输入操作员"></t-input>
</t-form-item>
<t-form-item label="票据类型" name="billType" :span="12" style="width: 16rem; margin-bottom: 0.5rem">
<t-select v-model="breakData.billType" clearable placeholder="请选择票据类型">
<t-option v-for="item in billType" :key="item.value" :label="item.label" :value="item.value" />
</t-select>
</t-form-item>
<t-form-item label="报损数量" name="breakNum" :span="12" style="margin-bottom: 0.5rem">
<t-input type="number" v-model="breakData.breakNum" placeholder="请输入报损数量"></t-input>
</t-form-item>
<t-form-item label="报损时间" name="breakDate" :span="10" style="width: 16rem; margin-bottom: 0.5rem">
<t-date-picker v-model="breakData.breakDate" placeholder="请选择报损时间" clearable />
</t-form-item>
<t-form-item label="报损原因" name="breakInfo" style="width: 33.6rem">
<t-textarea v-model="breakData.breakInfo" placeholder="请输入备注"></t-textarea>
</t-form-item>
<t-form-item />
<t-form-item>
<t-space size="small">
<t-button theme="primary" type="submit">提交</t-button>
<t-button theme="default" variant="base" type="reset">重置</t-button>
</t-space>
</t-form-item>
</t-form>
</div>
</t-space>
<t-space direction="vertical" v-if="props.activeForm === 'destroy'" style="width: 100%">
<div>
<t-form
ref="formDialog"
scroll-to-first-error="smooth"
label-align="left"
:rules="FORM_RULES_DESTROY"
:data="destroyData"
:colon="true"
@submit="destroySub"
label-width="calc(2em + 55px)"
layout="inline"
@reset="onReset"
>
<t-form-item label="审核状态" name="Status" style="margin-bottom: 0.5rem">
<t-radio-group v-model="destroyData.Status">
<t-radio value="1" @click="refuse = false">审核通过</t-radio>
<t-radio value="2" @click="refuse = true">审核拒绝</t-radio>
</t-radio-group>
</t-form-item>
<t-form-item />
<t-form-item label="拒绝原因" name="refuseInfo" v-if="refuse" style="width: 33.6rem; margin-bottom: 0.5rem">
<t-textarea v-model="destroyData.refuseInfo" placeholder="请输入备注"></t-textarea>
</t-form-item>
<t-form-item>
<t-space size="small">
<t-button theme="primary" type="submit">提交</t-button>
<t-button theme="default" variant="base" type="reset">重置</t-button>
</t-space>
</t-form-item>
</t-form>
</div>
</t-space>
</div>
</template>
<script setup>
import { billType } from "../codeValue/index";
import { ref, onMounted, onUpdated, watchEffect } from "vue";
const props = defineProps({
activeForm: {
type: String,
default: "",
},
editFrom: {
type: Object,
default: () => {},
},
});
const refuse = ref(false);
const emit = defineEmits();
//
const stockData = ref({
billserial: "",
stockNum: Number,
unit: "",
operator: "",
remark: "",
stockDate: "",
});
//
const FORM_RULES_STOCK = {
billserial: [{ required: true, message: "请输入票据编号", trigger: "blur" }],
billType: [{ required: true, message: "请选择票据类型", trigger: "change" }],
stockNum: [{ required: true, message: "请输入库存数量", trigger: "blur" }],
unit: [{ required: true, message: "请输入单位", trigger: "blur" }],
stockDate: [{ required: true, message: "请选择入库日期", trigger: "change" }],
operator: [{ required: true, message: "请输入操作员", trigger: "blur" }],
};
//
const stockAdd = async ({ validateResult, firstError }) => {
if (validateResult === true) {
await emit("childForm", stockData.value);
} else {
console.log("Validate Errors: ", firstError, validateResult);
}
};
// 退
const cancelData = ref({
approver: "",
approvalDate: "",
approvalReason: "",
});
//
const FORM_RULES_CANCEL = {
approver: [{ required: true, message: "请输入审批人", trigger: "blur" }],
approvalDate: [{ required: true, message: "请选择入库日期", trigger: "change" }],
approvalReason: [{ required: true, message: "请输入审批原因", trigger: "blur" }],
};
//
const cancelAdd = async ({ validateResult, firstError }) => {
if (validateResult === true) {
await emit("childForm");
} else {
console.log("Validate Errors: ", firstError, validateResult);
}
};
//
const receiptData = ref({
quitneckDate: "",
quitneckReason: "",
quitneckNum: "",
});
//
const FORM_RULES_RECEIPT = {
quitneckNum: [{ required: true, message: "请输入退领张数", trigger: "blur" }],
quitneckDate: [{ required: true, message: "请选择退领日期", trigger: "change" }],
quitneckReason: [{ required: true, message: "请输入退领原因", trigger: "blur" }],
};
//
const quitneckAdd = async ({ validateResult, firstError }) => {
if (validateResult === true) {
await emit("childForm", receiptData.value);
} else {
console.log("Validate Errors: ", firstError, validateResult);
}
};
//
const breakData = ref({
billserial: "",
operator: "",
billType: "",
breakNum: Number,
breakDate: "",
breakInfo: "",
});
//
const FORM_RULES_BREAK = {
billserial: [{ required: true, message: "请输入票据编号", trigger: "blur" }],
billType: [{ required: true, message: "请选择票据类型", trigger: "change" }],
breakNum: [{ required: true, message: "请输入报损数量", trigger: "blur" }],
breakDate: [{ required: true, message: "请选择报损日期", trigger: "change" }],
operator: [{ required: true, message: "请输入操作员", trigger: "blur" }],
breakInfo: [{ required: true, message: "请输入报损原因", trigger: "blur" }],
};
//
const breakSub = async ({ validateResult, firstError }) => {
if (validateResult === true) {
await emit("childForm", breakData.value);
} else {
console.log("Validate Errors: ", firstError, validateResult);
}
};
//
const destroyData = ref({
refuseInfo: "",
Status: "",
});
//
const FORM_RULES_DESTROY = {
Status: [{ required: true, message: "请选择审批状态", trigger: "change" }],
refuseInfo: [{ required: true, message: "请输入拒绝原因", trigger: "blur" }],
};
//
const destroySub = async ({ validateResult, firstError }) => {
if (validateResult === true) {
await emit("childForm", destroyData.value);
} else {
console.log("Validate Errors: ", firstError, validateResult);
}
};
//
const onReset = () => {};
onUpdated(() => {
//
if (props.activeForm === "stock") {
stockData.value = props.editFrom;
}
//
if (props.activeForm === "break") {
breakData.value = props.editFrom;
}
});
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,91 @@
<template>
<div class="centerC">
<div class="center-pie">
<pie :titleP="title" :dataP="data" :height="'15rem'" :width="'40rem'" />
</div>
<div class="center-bar">
<bar
:categories="categories"
:seriesData="seriesData"
:title="titlebar"
:legendList="legendList"
:height="'100%'"
:width="'52rem'"
/>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import pie from "@/components/echarts/pie.vue";
import bar from "@/components/echarts/bar.vue";
const title = ref("一天的开心程度");
const titlebar = ref("销售额");
const data = ref([
{ value: 50, name: "上午" },
{ value: 50, name: "下午" },
{ value: 100, name: "晚上" },
{ value: 200, name: "睡觉" },
]);
const categories = ref([
"一月",
"二月",
"三月",
"四月",
"五月",
"六月",
"七月",
"八月",
"九月",
"十月",
"十一月",
"十二月",
]);
const legendList = ["类别A", "类别B", "类别C"];
const seriesData = ref([
{
name: "类别A",
type: "bar",
data: [
1000, 1200, 1400, 1500, 1600, 1800, 1700, 1900, 2000, 2200, 2300, 2500,
],
},
{
name: "类别B",
type: "bar",
data: [200, 400, 1000, 500, 700, 800, 1000, 1100, 1150, 1200, 1300, 1400],
},
{
name: "类别C",
type: "bar",
data: [
800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900,
],
},
]);
</script>
<style lang="less" scoped>
.centerC {
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
.center-pie {
width: 49%;
height: 100%;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
.center-bar {
width: 49%;
height: 100%;
background-color: #fff;
}
}
</style>

View File

@ -0,0 +1,53 @@
<template>
<div class="linebox">
<line-chart
:categories="categories"
:seriesData="seriesData"
:titleP="title"
:legendList="legendList"
:height="'100%'"
:width="'100rem'"
/>
</div>
</template>
<script setup>
import lineChart from "@/components/echarts/line.vue";
import { ref } from "vue";
const title = ref("折线图");
const categories = ref([
"一月",
"二月",
"三月",
"四月",
"五月",
"六月",
"七月",
"八月",
"九月",
"十月",
"十一月",
"十二月",
]);
const legendList = ref(["服务一", "服务二"]);
const seriesData = ref([
{
name: "服务一",
data: [10, 20, 15, 20, 25, 30, 15, 22, 18, 28, 25, 32],
type: "line",
}, //
{
name: "服务二",
data: [15, 22, 18, 28, 25, 32, 10, 20, 15, 20, 25, 30],
type: "line",
}, //
]);
</script>
<style lang="less" scoped>
.linebox {
width: 100%;
height: 100%;
}
</style>

View File

@ -0,0 +1,90 @@
<template>
<div class="headerC">
<div class="header_box" v-for="(item, index) in homeTitle" :key="index">
<div class="header_box">
<div class="header_icon">
<t-icon :name="item.icon" class="icon" />
</div>
<div class="content">
<div class="title">{{ item.title }}</div>
<div class="num">{{ item.num }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
const homeTitle = ref([
{
title: "今日发票数",
num: "23张",
icon: "face-retouching",
},
{
title: "今日学生投诉数",
num: "555555",
icon: "crooked-smile",
},
{
title: "今日教的学费",
num: "0",
icon: "despise",
},
{
title: "今日赔偿费",
num: "5000,0000,0000",
icon: "flip-smiling-face",
},
{
title: "今日彩票中奖数",
num: "0",
icon: "cat",
},
]);
</script>
<style lang="less" scoped>
.headerC {
height: 100%;
justify-content: space-between;
display: flex;
}
.header_box {
height: 100%;
width: 20rem;
background-color: #fff;
display: flex;
}
.header_icon {
width: 30%;
height: 100%;
display: flex;
margin-right: 1rem;
align-items: center;
justify-content: flex-end;
.icon {
width: 3rem;
height: 3rem;
color: #366ef4;
}
}
.content {
width: 70%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
.title {
font-size: 1.2rem;
color: #666;
margin-bottom: 0.5rem;
font-weight: 600;
}
.num {
color: #85d3ff;
font-weight: 600;
}
}
</style>

41
src/pages/home/index.vue Normal file
View File

@ -0,0 +1,41 @@
<template>
<div class="back-color">
<t-layout style="height: 100%; background-color: #f5f7fb">
<t-header class="header">
<home-header />
</t-header>
<t-content class="content">
<home-center />
</t-content>
<t-content class="footer">
<home-footer />
</t-content>
</t-layout>
</div>
</template>
<script setup>
import homeHeader from "./components/homeHeader.vue";
import homeCenter from "./components/homeCenter.vue";
import homeFooter from "./components/homeFooter.vue";
</script>
<style lang="less" scoped>
.header {
height: 15%;
width: 100%;
margin-bottom: 1rem;
background-color: #f5f7fb;
}
.content {
height: 15%;
width: 100%;
margin-bottom: 1rem;
}
.footer {
height: 15%;
width: 100%;
background-color: #fff;
margin-bottom: 1rem;
}
</style>

188
src/pages/login/index.vue Normal file
View File

@ -0,0 +1,188 @@
<template>
<div class="login-container">
<div style="width: 100%" class="login-right">
<div class="login-form">
<div class="login-box">
<t-form
:data="formData"
:rules="rules"
ref="form"
@reset="onReset"
@submit="onSubmit"
:colon="true"
:labelWidth="0"
>
<h2 class="login-title">登录</h2>
<t-form-item label="账号" name="account">
<t-input
clearable
v-model="formData.account"
placeholder="请输入工号或学号"
>
<desktop-icon slot:string="prefix-icon"></desktop-icon>
</t-input>
</t-form-item>
<t-form-item label="密码" name="password">
<t-input
type="password"
clearable
v-model="formData.password"
placeholder="请输入密码"
>
<lock-on-icon slot:string="prefix-icon"></lock-on-icon>
</t-input>
</t-form-item>
<t-form-item class="form-actions">
<t-button theme="primary" type="submit" block>登录</t-button>
<div class="forgot-password-spacer"></div>
<t-button
type="text"
@click="handleForgotPasswordClick"
class="text"
>修改密码</t-button
>
</t-form-item>
</t-form>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { MessagePlugin } from "tdesign-vue-next";
import { reactive, ref, onMounted } from "vue";
import { reqUser } from "@/api/login";
import { useRouter } from "vue-router";
// import axios from 'axios';
// import { TForm, TFormItem, TInput, TButton } from "tdesign-vue-next";
// import { DesktopIcon, LockOnIcon } from "tdesign-icons-vue";
const INITIAL_DATA = {
account: "",
password: "",
};
const from = ref(null);
const router = useRouter();
const formData = reactive({
...INITIAL_DATA,
});
const rules = reactive({
account: [
{
required: true,
message: "必须填写",
},
{
pattern: /^\d{10}$/, // 10
message: "学号必须是10位数字",
},
],
password: [
// {
// required: false,
// message: "",
// },
// {
// len: 8,
// message: " 8 ",
// },
// {
// message: "",
// },
],
});
const onSubmit = async () => {
const data1 = {
username: formData.account,
password: formData.password,
};
const { data } = await reqUser(data1);
if (data === true) {
MessagePlugin.success("登录成功");
router.push("/");
} else {
MessagePlugin.error("登录失败");
}
// try {
// if (!form || !form.value) {
// console.warn("form form.value ");
// return;
// }
// const validateResult = await form.value?.validate();
// if (validateResult?.result) {
// MessagePlugin.success("");
// await router.push("/");
// } else {
// const firstError = validateResult?.errors[0]?.message || "";
// console.log("Errors: ", validateResult.errors);
// MessagePlugin.warning(firstError);
// }
// } catch (error) {
// console.error(":", error);
// MessagePlugin.error("");
// }
};
function handleForgotPasswordClick() {
router.push("/password-reset");
}
</script>
<style lang="less" scoped>
.login-container {
display: flex;
position: absolute;
width: 100%;
height: 100%;
background: url(../../assets/bg.jpg);
background-size: cover;
overflow: hidden;
}
.login-form {
width: 26%;
height: 40%;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 1.25rem;
}
.login-title {
text-align: center;
font-size: 1.5rem;
margin-bottom: 4rem;
color: #333;
}
.login-box {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.login-right {
width: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.form-actions {
display: flex;
justify-content: space-between;
}
.forgot-password-spacer {
flex-grow: 1;
width: 0;
height: 0;
margin-left: 3rem;
}
.text {
padding-left: 1.8rem;
padding-right: 1.8rem;
}
</style>

View File

@ -0,0 +1,170 @@
<template>
<div class="password-container">
<div class="password-form">
<t-form
:data="formData"
:rules="rules"
ref="form"
@reset="onReset"
@submit="onSubmit"
@validate="onValidate"
>
<t-form-item label="学号" name="account">
<t-input
v-model="formData.account"
placeholder="请输入学号"
></t-input>
</t-form-item>
<t-form-item label="密码" name="password">
<t-input
type="password"
v-model="formData.password"
placeholder="请输入密码"
></t-input>
</t-form-item>
<t-form-item label="确认密码" name="rePassword">
<t-input
type="password"
v-model="formData.rePassword"
placeholder="请再次输入密码"
></t-input>
</t-form-item>
<t-form-item style="margin-left: 6rem">
<t-space size="10px">
<t-button theme="primary" type="submit">提交</t-button>
<t-button theme="default" variant="base" type="reset"
>重置</t-button
>
</t-space>
</t-form-item>
</t-form>
</div>
</div>
</template>
<script setup>
import { MessagePlugin } from "tdesign-vue-next";
import { reactive } from "vue";
import router from "@/router";
import {reqPassword} from "@/api/password"
const INITIAL_DATA = {
account: "",
password: "",
rePassword: "",
};
const formData = reactive({
...INITIAL_DATA,
});
const rePassword = (val) =>
new Promise((resolve) => {
const timer = setTimeout(() => {
resolve(formData.password === val);
clearTimeout(timer);
});
});
const rules = reactive({
account: [
{
required: true,
message: "学号必填",
type: "error",
},
{
pattern: /^\d{10}$/, // 10
message: "学号必须是10位数字",
},
],
password: [
{
required: true,
message: "密码必填",
type: "error",
},
{
len: 8,
message: "请输入 8 位密码",
},
{
pattern: /^(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{8,}$/u,
message: "密码必须包含至少一个大写字母,并由字母和数字组成",
},
],
rePassword: [
{
required: true,
message: "密码必填",
type: "error",
},
{
len: 8,
message: "请输入 8 位密码",
},
{
pattern: /[A-Z]+/,
message: "密码必须包含大写字母",
},
{
validator: rePassword,
trigger: ["blur", "change"],
message: "两次密码不一致",
},
],
});
const onReset = () => {
MessagePlugin.success("重置成功");
};
const onSubmit = async () => {
try {
const validateResult = await from.value?.validate();
if (validateResult?.result) {
await reqPassword(formData.account, formData.password, formData.rePassword);
MessagePlugin.success("提交成功");
await router.push("/");
} else {
const firstError = validateResult?.errors[0]?.message || "未知错误";
console.log("Errors: ", validateResult.errors);
MessagePlugin.warning(firstError);
}
} catch (error) {
console.error("请求失败:", error);
MessagePlugin.error("提交失败");
}
};
const onValidate = ({ validateResult, firstError }) => {
if (validateResult === true) {
onSubmit();
console.log("Validate Success");
} else {
console.log("Validate Errors: ", firstError, validateResult);
}
};
</script>
<style lang="less" scoped>
.password-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-image: url(../../assets/bg.jpg);
background-size: cover;
padding: 2rem;
}
.password-form {
width: 26%;
height: 35%;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 1.25rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>

View File

@ -0,0 +1,142 @@
<template>
<div class="back-color">
<div class="form">
<t-form
:data="formData"
reset-type="initial"
colon
@reset="onReset"
@submit="onSubmit"
>
<t-row>
<t-col :span="3">
<t-form-item label="学生姓名" name="name">
<t-input v-model="formData.name"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生学号" name="studentnumber">
<t-input v-model="formData.studentnumber"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生学院" name="college">
<t-input v-model="formData.college"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="导员姓名" name="tutor">
<t-input v-model="formData.tutor"></t-input>
</t-form-item>
</t-col>
</t-row>
<t-row style="margin-top: 0.5rem">
<t-col :push="10" :span="2" style="margin-top: 0.2rem">
<t-row :gutter="75">
<t-col :offset="3" :span="3">
<t-button type="submit">搜索</t-button>
</t-col>
<t-col :span="3">
<t-button type="reset">重置</t-button>
</t-col>
</t-row>
</t-col>
</t-row>
</t-form>
</div>
<div class="table">
<t-table
row-key="id"
:data="tableData"
:columns="columns"
:hover="true"
table-layout="auto"
:pagination="pagination"
:show-header="true"
cell-empty-content="-"
max-height="550"
lazy-load
@page-change="onPageChange"
:loading="loading"
>
</t-table>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, reactive } from 'vue'
import {
APIPremiumList,
APIPremiumFind
} from '@/api/receivables-management/management'
//
const tableData = ref([])
//
const formData = reactive({
name: '',
studentnumber: '',
college: '',
tutor: ''
})
//
const columns = ref([
{ colKey: 'serial-number', title: '学生序号', align: 'center' },
{ colKey: 'name', title: '学生姓名', align: 'center' },
{ colKey: 'studentNumber', title: '学号', align: 'center' },
{ colKey: 'gender', title: '性别', align: 'center' },
{ colKey: 'age', title: '年龄', align: 'center' },
{ colKey: 'tuition', title: '欠费金额', align: 'center' },
{ colKey: 'enrollmentyear', title: '入学年份', align: 'center' },
{ colKey: 'college', title: '所在学院', align: 'center' },
{ colKey: 'major', title: '所在专业', align: 'center' },
{ colKey: 'grade', title: '所在班级', align: 'center' },
{ colKey: 'tutor', title: '导员姓名', align: 'center' }
])
//
let pagination = {
defaultCurrent: 1,
defaultPageSize: 10,
total: 50
}
//
const loading = ref(false)
//
const PremiumList = async () => {
const res = await APIPremiumList()
tableData.value = res.data.list
pagination.total = res.data.list.length
}
//
const onPageChange = (Newpage, PreviousPagePrev) => {
loading.value = true
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const onReset = () => {
loading.value = true
const timerId = setTimeout(() => {
PremiumList()
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const onSubmit = async () => {
const data = await APIPremiumFind(formData)
tableData.value = data
pagination.total = data.length
}
onMounted(() => {
PremiumList()
})
</script>
<style lang="less" scoped>
.table {
margin-top: 1rem;
}
</style>

View File

@ -0,0 +1,362 @@
<template>
<div class="back-color">
<div>
<t-button @click="backToHome">返回</t-button>
</div>
<div>
<div class="invoiceContainer">
<div class="invoiceHeade">
<div class="headeLeft"></div>
<div class="headeMiddle">
<span class="title">xxx增值税电子普通发票</span>
<hr />
<hr />
</div>
<div class="headeRight">
<ul>
<li><label> 发票代码 </label><span>1234</span></li>
<li><label> 发票号码 </label><span>223</span></li>
<li>
<label> 开票日期 </label><span>{{ InvoiceData.xdate }}</span>
</li>
<li><label> 校验码 </label><span>111111</span></li>
</ul>
</div>
</div>
<div class="invoiceBody">
<div class="userInfo">
<div class="buy">缴费方</div>
<div class="buyInfo">
<ul>
<li>
<label>学生姓名</label><span>{{ InvoiceData.xname }}</span>
</li>
<li>
<label>学号</label><span>{{ InvoiceData.xstudent }}</span>
</li>
<li style="display: flex">
<label>电话</label
><t-input
size="small"
style="width: 300px"
v-model="InvoiceData.xphone"
/>
</li>
<li style="display: flex">
<label>缴费方式</label
><t-input
size="small"
style="width: 300px"
v-model="InvoiceData.xpayment"
/>
</li>
</ul>
</div>
<div class="password">缴费方</div>
<div class="department">
<ul>
<li>
<label>学生部门</label
><span>{{ InvoiceData.xdepartment }}</span>
</li>
<li>
<label>学生班级</label><span>{{ InvoiceData.xgrade }}</span>
</li>
</ul>
</div>
</div>
<div class="Table">
备入
<div>
<t-textarea
placeholder="请输入内容"
v-model="InvoiceData.xremark"
/>
</div>
</div>
<div class="saleInfo">
<div class="total">价税合计(大写)</div>
<span class="max"
><t-input
size="small"
style="width: 150px; padding-top: 0.2rem"
v-model="InvoiceData.xchargebig"
/></span>
<div class="total2" style="display: flex">
(小写)
<span style="display: flex"
><t-input
size="small"
style="width: 150px; padding-top: 0.2rem"
v-model="InvoiceData.xcharge"
/>
</span>
</div>
</div>
<div class="userInfo2">
<div class="buy">收费方</div>
<div class="buyInfo">
<ul>
<li><label>名称</label><span>xxxxxxx学院</span></li>
<li>
<label>纳税人识别号</label><span>12443536377484848</span>
</li>
<li>
<label>地址&nbsp;&nbsp;&nbsp;电话</label
><span>11223443532</span>
</li>
<li><label>开户行及账号</label><span>中国农业银行</span></li>
</ul>
</div>
<div class="remark">备注</div>
</div>
<div class="userInfo3">
<ul class="invoicetFooter" style="display: flex">
<li style="display: flex">
<label>收款人:</label
><t-input
size="small"
style="width: 100px"
v-model="InvoiceData.xpayee"
/>
</li>
<li style="display: flex">
<label>复核:</label
><t-input
size="small"
style="width: 100px"
v-model="InvoiceData.xreviewer"
/>
</li>
<li style="display: flex">
<label>开票人:</label
><t-input
size="small"
style="width: 100px"
v-model="InvoiceData.xdrawer"
/>
</li>
<li><label>销售方</label></li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
import dayjs from 'dayjs'
const Route = useRoute()
const Router = useRouter()
//
const InvoiceData = ref({
//
xdate: dayjs().format('YYYY-MM-DD'),
//
xname: Route.query.firstName,
//
xstudent: 12346,
//
xphone: '',
//
xpayment: '',
//
xdepartment: Route.query.status,
//
xgrade: Route.query.classname,
//
xremark: '',
// ()
xcharge: Route.query.letters ? Route.query.letters[0] : 0,
// ()
xchargebig: '',
//
xpayee: '',
//
xreviewer: '',
//
xdrawer: ''
})
const backToHome = () => {
Router.go(-1)
}
</script>
<style lang="scss" scoped>
.headeRight {
width: 240px;
height: 100%;
font-size: 16px;
line-height: 30px;
text-align: left;
float: left;
}
.headeRight > ul {
display: inline-block;
margin-left: 16px;
margin-top: 10px;
}
.invoicetFooter > li {
margin-top: 16px;
margin-right: 100px;
margin-left: 11px;
display: inline-block;
}
.max {
display: inline-block;
margin-top: 5px;
margin-left: 4px;
}
.total {
width: 270px;
height: 100%;
font-size: 17px;
line-height: 30px;
text-align: center;
border-right: 1px solid black;
float: left;
padding-top: 0.25rem;
}
.total2 {
width: 270px;
height: 100%;
font-size: 17px;
line-height: 30px;
text-align: center;
margin-right: 130px;
float: right;
margin-top: 0.25rem;
}
.buyer {
width: 30px;
height: 100%;
font-size: 17px;
text-align: center;
border-right: 1px solid black;
float: left;
}
.title {
font-size: 33px;
display: inline-block;
margin-top: 50px;
font-family: '仿宋';
}
.headeMiddle {
width: 400px;
height: 100%;
font-size: 17px;
line-height: 30px;
text-align: center;
float: left;
}
.headeLeft {
width: 300px;
height: 100%;
font-size: 17px;
line-height: 30px;
text-align: center;
float: left;
}
.buy {
width: 30px;
height: 100%;
font-size: 17px;
line-height: 30px;
text-align: center;
border-right: 1px solid black;
border-left: 1px solid black;
float: left;
}
.buyInfo {
width: 510px;
height: 100%;
font-size: 16px;
line-height: 25px;
text-align: left;
border-right: 1px solid black;
float: left;
}
.department {
height: 100%;
font-size: 16px;
line-height: 25px;
text-align: left;
float: left;
}
.password {
width: 30px;
height: 100%;
font-size: 17px;
line-height: 30px;
text-align: center;
border-right: 1px solid black;
float: left;
}
.remark {
width: 30px;
height: 100%;
font-size: 17px;
line-height: 50px;
text-align: center;
border-right: 1px solid black;
float: left;
}
ul {
list-style-type: none;
margin: 0;
padding-left: 5px;
}
.invoiceContainer {
width: 1000px;
margin: 0 auto;
border-top: 1px solid black;
}
.invoiceHeade {
width: 1000px;
height: 140px;
border-bottom: 1px solid black;
border-left: 1px solid black;
border-right: 1px solid black;
}
.userInfo {
width: 1000px;
height: 100px;
border-bottom: 1px solid black;
border-right: 1px solid black;
}
.userInfo2 {
width: 1000px;
height: 100px;
border-right: 1px solid black;
}
.userInfo3 {
width: 1000px;
height: 100px;
border-top: 1px solid black;
}
.Table {
width: 999px;
height: 400px;
border-bottom: 1px solid black;
border-left: 1px solid black;
border-right: 1px solid black;
}
.sum {
width: 1000px;
height: 50px;
border-bottom: 1px solid black;
}
.saleInfo {
width: 999px;
height: 40px;
border-bottom: 1px solid black;
border-right: 1px solid black;
border-left: 1px solid black;
}
</style>

View File

@ -0,0 +1,146 @@
<template>
<div class="back-color">
<div class="form">
<t-form
:data="formData"
reset-type="initial"
colon
@reset="onReset"
@submit="onSubmit"
>
<t-row>
<t-col :span="3">
<t-form-item label="学生姓名" name="name">
<t-input v-model="formData.name"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生学号" name="studentnumber">
<t-input v-model="formData.studentnumber"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生学院" name="college">
<t-input v-model="formData.college"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="导员姓名" name="tutor">
<t-input v-model="formData.tutor"></t-input>
</t-form-item>
</t-col>
</t-row>
<t-row style="margin-top: 0.5rem">
<t-col :push="10" :span="2" style="margin-top: 0.2rem">
<div
style="
display: flex;
justify-content: space-between;
width: 8vw;
margin-left: 4.5vw;
"
>
<t-button type="submit">搜索</t-button>
<t-button type="reset">重置</t-button>
</div>
</t-col>
</t-row>
</t-form>
</div>
<div class="table">
<t-table
row-key="id"
:data="tableData"
:columns="columns"
:hover="true"
table-layout="auto"
:pagination="pagination"
:show-header="true"
cell-empty-content="-"
max-height="550"
lazy-load
@page-change="onPageChange"
:loading="loading"
>
</t-table>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, reactive } from 'vue'
import {
APIMitigateList,
APIMitigateFind
} from '@/api/receivables-management/management'
//
const tableData = ref([])
//
const formData = reactive({
name: '',
studentnumber: '',
college: '',
tutor: ''
})
//
const columns = ref([
{ colKey: 'serial-number', title: '学生序号', align: 'center' },
{ colKey: 'name', title: '学生姓名', align: 'center' },
{ colKey: 'studentNumber', title: '学号', align: 'center' },
{ colKey: 'gender', title: '性别', align: 'center' },
{ colKey: 'age', title: '年龄', align: 'center' },
{ colKey: 'tuition', title: '学费金额', align: 'center' },
{ colKey: 'mitigate', title: '减免金额', align: 'center' },
{ colKey: 'enrollmentyear', title: '入学年份', align: 'center' },
{ colKey: 'college', title: '所在学院', align: 'center' },
{ colKey: 'major', title: '所在专业', align: 'center' },
{ colKey: 'grade', title: '所在班级', align: 'center' },
{ colKey: 'tutor', title: '导员姓名', align: 'center' }
])
//
let pagination = {
defaultCurrent: 1,
defaultPageSize: 10,
total: 50
}
//
const loading = ref(false)
//
const MitigateList = async () => {
const res = await APIMitigateList()
tableData.value = res.data.list
pagination.total = res.data.list.length
}
//
const onPageChange = (Newpage, PreviousPagePrev) => {
loading.value = true
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const onReset = () => {
loading.value = true
const timerId = setTimeout(() => {
MitigateList()
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const onSubmit = async () => {
const res = await APIMitigateFind(formData)
tableData.value = res
pagination.total = res.length
}
onMounted(() => {
MitigateList()
})
</script>
<style lang="less" scoped>
.table {
margin-top: 1rem;
}
</style>

View File

@ -0,0 +1,74 @@
<template>
<button @click="start">start</button>
<button @click="pause">pause</button>
<button @click="disabled = true">disabled</button>
<div class="flex">
<VueDraggable
ref="el"
v-model="list"
:disabled="disabled"
:animation="150"
ghostClass="ghost"
class="flex flex-col gap-2 p-4 w-300px h-300px m-auto bg-gray-500/5 rounded"
@start="onStart"
@update="onUpdate"
>
<div
v-for="item in list"
:key="item.id"
class="cursor-move h-30 bg-gray-500/5 rounded p-3 cursor-move"
>
{{ item.name }}
</div>
</VueDraggable>
<preview-list :list="list" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { type UseDraggableReturn, VueDraggable } from 'vue-draggable-plus'
const list = ref([
{
name: 'Joao',
id: 1
},
{
name: 'Jean',
id: 2
},
{
name: 'Johanna',
id: 3
},
{
name: 'Juan',
id: 4
}
])
const el = ref<UseDraggableReturn>()
const disabled = ref(false)
function pause() {
el.value?.pause()
}
function start() {
el.value?.start()
}
const onStart = () => {
console.log('start')
}
const onUpdate = () => {
console.log('update')
}
</script>
<style scoped>
.ghost {
opacity: 0.5;
background: #c8ebfb;
}
</style>

View File

@ -0,0 +1,333 @@
<template>
<div class="back-color">
<div class="form">
<t-form
ref="form"
:data="formData"
reset-type="initial"
colon
@reset="onReset"
@submit="onSubmit"
>
<t-row>
<t-col :span="3">
<t-form-item label="姓名" name="name">
<t-input v-model="formData.name"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学号" name="studentnumber">
<t-input v-model="formData.studentnumber"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="部门" name="studentnumber">
<t-tree-select
v-model="formData.department"
:data="DEPARTMENT"
clearable
/>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="专业" name="major">
<t-tree-select v-model="formData.major" :data="MAJOR" clearable />
</t-form-item>
</t-col>
</t-row>
<t-row style="margin-top: 0.5rem">
<t-col :span="3">
<t-form-item label="班级" name="grade">
<t-tree-select v-model="formData.grade" :data="GRADE" clearable />
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="其他条件" name="tuition">
<t-tree-select
v-model="formData.tuition"
:data="CONDITION"
clearable
/>
</t-form-item>
</t-col>
<t-col :span="6" style="margin-top: 0.2rem">
<t-row>
<t-col :offset="9" :span="1">
<t-button type="submit">搜索</t-button>
</t-col>
<t-col :span="1"> </t-col>
<t-col :span="1">
<t-button type="reset">重置</t-button>
</t-col>
</t-row>
</t-col>
</t-row>
</t-form>
</div>
<div class="table">
<t-table
row-key="id"
:data="tableData"
:columns="columns"
:hover="true"
table-layout="auto"
:pagination="pagination"
:show-header="true"
cell-empty-content="-"
max-height="500"
lazy-load
@row-click="handleRowClick"
@page-change="onPageChange"
:loading="loading"
>
<template #action="{ row }">
<t-button
v-if="row.tuition === '未缴学费'"
theme="danger"
@click="handleTicket(row)"
>清缴学费</t-button
>
<t-button v-else @click="hreturn(row)">退还学费</t-button>
</template>
</t-table>
</div>
<div>
<t-button style="margin-top: 1rem" type="primary" @click="handleExport"
>导出excel表格</t-button
>
</div>
</div>
</template>
<script setup lang="jsx">
import { ref, reactive, onMounted } from 'vue'
import {
APIReceivablesList,
APIReceivablesAdd
} from '@/api/receivables-management/management'
import { useRouter } from 'vue-router'
import { ExcelUtils } from '@/utils/excel'
const router = useRouter()
//
const formData = reactive({
name: '',
studentnumber: '',
department: '',
major: '',
grade: '',
tuition: ''
})
//
const DEPARTMENT = [
{
label: '机电工程系',
value: '机电工程系'
},
{
label: '护理分院',
value: '护理分院'
},
{
label: '建筑系',
value: '建筑系'
},
{
label: '材料科学与工程系',
value: '材料科学与工程系'
},
{
label: '环境科学与工程系',
value: '环境科学与工程系'
}
]
//
const MAJOR = [
{
label: '机械制造与自动化',
value: '机械制造与自动化'
},
{
label: '材料科学与工程',
value: '材料科学与工程'
},
{
label: '环境科学与工程',
value: '环境科学与工程'
},
{
label: '建筑工程',
value: '建筑工程'
},
{
label: '护理学',
value: '护理学'
}
]
//
const GRADE = [
{
label: '机制1班',
value: '机制1班'
},
{
label: '材料1班',
value: '材料1班'
},
{
label: '环境1班',
value: '环境1班'
},
{
label: '建筑1班',
value: '建筑1班'
},
{
label: '护理1班',
value: '护理1班'
}
]
//
const CONDITION = [
{
label: '已付学费',
value: '已付学费'
},
{
label: '未缴学费',
value: '未缴学费'
}
]
//
const tableData = ref([])
//
const columns = ref([
{ colKey: 'serial-number' },
{ colKey: 'name', title: '姓名' },
{ colKey: 'studentnumber', title: '学号' },
{ colKey: 'department', title: '部门' },
{ colKey: 'major', title: '专业' },
{ colKey: 'grade', title: '班级' },
{
colKey: 'tuition',
title: '是否缴费',
cell: (h, { row }) => {
return (
<div>
{row.tuition === '未缴学费' ? (
<t-tag theme='danger'>{row.tuition}</t-tag>
) : (
<t-tag theme='success'>{row.tuition}</t-tag>
)}
</div>
)
}
},
{
colKey: 'action',
title: '操作',
align: 'center'
}
])
//
let pagination = {
defaultCurrent: 1,
defaultPageSize: 10,
total: 50
}
//
const onSubmit = async () => {
if (
formData.name ||
formData.studentnumber ||
formData.department ||
formData.major ||
formData.grade ||
formData.tuition
) {
const res = await APIReceivablesAdd(formData)
console.log(res)
tableData.value = Array.from(res)
pagination.total = res.length
} else {
alert('请填写完整信息')
}
}
//
const loading = ref(false)
//
const onReset = () => {
ReceivablesList()
}
//
const handleRowClick = e => {
console.log(e)
}
//
const ReceivablesList = async () => {
loading.value = true
const res = await APIReceivablesList()
tableData.value = res.data.list
pagination.total = res.data.list.length
loading.value = false
}
//
const onPageChange = (Newpage, PreviousPagePrev) => {
loading.value = true
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const handleTicket = row => {
router.push({
path: '/billCollected',
query: row
})
}
//退
const hreturn = row => {
router.push({
path: 'bill-bill'
})
}
//excel
const handleExport = () => {
const title = '报表明细excel'
const titleFile = '报表明细'
const columns = [
{ header: '姓名', key: '1', width: 20 },
{ header: '学号', key: '2', width: 20 },
{ header: '部门', key: '3', width: 20 },
{ header: '专业', key: '4', width: 20 },
{ header: '班级', key: '5', width: 20 },
{ header: '是否缴费', key: '6', width: 20 }
]
const addRow = []
tableData.value.forEach(item => {
addRow.push({
1: item.name,
2: item.studentnumber,
3: item.department,
4: item.major,
5: item.grade,
6: item.tuition
})
})
// excel
ExcelUtils(title, titleFile, columns, addRow)
}
onMounted(() => {
ReceivablesList()
})
</script>
<style scoped lang="less">
.form {
background-color: #fff;
height: 6rem;
padding-top: 0.5rem;
}
.table {
margin-top: 1rem;
}
</style>

View File

@ -0,0 +1,365 @@
<template>
<div class="back-color">
<div>
<t-table
ref="tableRef"
row-key="key"
:columns="columns"
:data="data"
:editable-cell-state="editableCellState"
bordered
lazy-load
>
<template #operation="{ row }">
<t-button theme="default" variant="text" @click="handleEdit(row)"
>填写电子票据</t-button
>
<t-button theme="default" variant="text" @click="waivarForm(row)"
>申请为减免学生</t-button
>
</template>
</t-table>
</div>
<div v-if="judge()">
<div
style="
font-size: 2rem;
height: 5rem;
line-height: 5rem;
text-align: center;
"
>
管理学生收费
</div>
<div>
<div>
<t-row justify="end">
<t-col span="2">
<t-button theme="default" variant="text" @click="onClick"
>添加收费标准</t-button
>
</t-col>
</t-row>
</div>
<t-base-table
row-key="index"
:data="RATES_OPTIONS"
:columns="ratesColumns"
@page-change="onPageChange"
:pagination="pagination"
max-height="500"
>
<template #operation="{ row }">
<t-button theme="default" variant="text" @click="Role(row)"
>编辑</t-button
>
<t-button theme="default" variant="text" @click="DeleteRole(row)"
>删除</t-button
>
</template>
</t-base-table>
</div>
</div>
<div>
<t-space>
<t-dialog
v-model:visible="visible"
header="添加学生收费标准"
width="30%"
:on-cancel="onCancel"
:on-close-btn-click="onCloseBtnClick"
:on-confirm="onConfirmAnother"
:close-on-overlay-click="false"
>
<t-space direction="vertical" style="width: 100%">
<t-space direction="vertical" size="large">
<t-form
ref="form"
:data="formData"
reset-type="initial"
colon
@reset="onReset"
>
<t-form-item label="学生状态" name="name">
<t-input v-model="formData.name"></t-input>
</t-form-item>
<t-form-item label="应收金额" name="RoutingAddress">
<t-input v-model="formData.RoutingAddress"></t-input>
</t-form-item>
</t-form>
</t-space>
</t-space>
</t-dialog>
</t-space>
</div>
</div>
</template>
<script setup lang="jsx">
import { ref, computed, reactive, watchEffect } from 'vue'
import { Input, Select } from 'tdesign-vue-next'
import { useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
import dayjs from 'dayjs'
const route = useRoute()
const router = useRouter()
const initData = reactive(
new Array(1).fill(null).map((_, i) => ({
key: String(i + 1),
//
firstName: route.query.name,
//
status: route.query.department,
//
classname: route.query.grade,
letters: [],
createTime: dayjs().format('YYYY-MM-DD')
}))
)
//
const STATUS_OPTIONS = [
{ label: '机电工程系', value: '机电工程系' },
{ label: '护理分院', value: '护理分院' },
{ label: '建筑系', value: '建筑系' },
{ label: '材料科学与工程系', value: '材料科学与工程系' },
{ label: '审批环境科学与工程系过期', value: '审批环境科学与工程系过期' }
]
//
const CLASS_NAME = [
{ label: '机制1班', value: '机制1班' },
{ label: '材料1班', value: '材料1班' },
{ label: '环境1班', value: '环境1班' },
{ label: '建筑1班', value: '建筑1班' },
{ label: '护理1班', value: '护理1班' }
]
//
let RATES_OPTIONS = reactive([
{ label: '机电工程系', value: '16800元' },
{ label: '护理分院', value: '19800元' },
{ label: '建筑系', value: '9800元' },
{ label: '材料科学与工程系', value: '20000元' }
])
//
const ratesColumns = [
{ title: '学生收费标准', colKey: 'label' },
{
title: '学生应收费',
colKey: 'value'
},
{
title: '操作',
colKey: 'operation',
width: 200,
align: 'center'
}
]
//
const formData = ref({
name: '',
RoutingAddress: ''
})
//
const pagination = ref({
defaultPageSize: 5,
total: RATES_OPTIONS.length,
defaultCurrent: 1
})
const visible = ref(false)
const align = ref('left')
const data = ref([...initData])
const editableCellState = cellParams => {
const { row } = cellParams
return row.status !== 2
}
const tableRef = ref()
//
const columns = computed(() => [
{
title: '学生姓名',
colKey: 'firstName',
align: align.value,
edit: {
component: Input,
props: {
clearable: true,
autofocus: true
},
validateTrigger: 'change',
on: editContext => ({
onBlur: () => {
console.log('失去焦点', editContext)
},
onEnter: ctx => {
ctx?.e?.preventDefault()
console.log('onEnter', ctx)
}
}),
abortEditOnEvent: ['onEnter'],
onEdited: context => {
console.log(context)
const newData = [...data.value]
newData.splice(context.rowIndex, 1, context.newRowData)
data.value = newData
console.log('Edit firstName:', context)
},
defaultEditable: true
}
},
{
title: '学生部门',
colKey: 'status',
cell: (h, { row }) =>
STATUS_OPTIONS.find(t => t.value === row.status)?.label,
edit: {
component: Select,
props: {
clearable: true,
options: STATUS_OPTIONS
},
on: editContext => ({
onChange: params => {
console.log('status changed', editContext, params)
}
}),
onEdited: context => {
data.value.splice(context.rowIndex, 1, context.newRowData)
}
}
},
{
title: '学生班级',
colKey: 'classname',
cell: (h, { row }) =>
CLASS_NAME.find(t => t.value === row.classname)?.label,
edit: {
component: Select,
props: {
clearable: true,
options: CLASS_NAME
},
on: editContext => ({
onChange: params => {
console.log('status changed', editContext, params)
}
}),
onEdited: context => {
data.value.splice(context.rowIndex, 1, context.newRowData)
}
}
},
{
title: '学生状态',
colKey: 'letters',
cell: (h, { row }) => row.letters.join('、'),
edit: {
keepEditMode: true,
component: Select,
props: () => {
return {
multiple: true,
minCollapsedNum: 1,
options: RATES_OPTIONS.filter(t =>
t.show === undefined ? true : t.show()
)
}
},
onEdited: context => {
data.value.splice(context.rowIndex, 1, context.newRowData)
}
}
},
{
title: '应缴金额',
colKey: 'letters',
cell: (h, { row }) => row.letters.join('、'),
edit: {
keepEditMode: true,
component: Select,
props: () => {
return {
multiple: true,
minCollapsedNum: 1
}
},
onEdited: context => {
data.value.splice(context.rowIndex, 1, context.newRowData)
}
}
},
{
title: '创建日期',
colKey: 'createTime'
},
{
title: '操作',
width: 300,
colKey: 'operation',
align: 'center'
}
])
//
const handleEdit = row => {
router.push({
path: '/bill-bill',
query: row
})
}
//
const waivarForm = row => {
router.push({
path: '/waivar-form',
query: row
})
}
//
const onClick = context => {
console.log('点击了确认按钮,弹出弹窗', context)
visible.value = true
}
const onConfirmAnother = context => {
console.log('点击了确认按钮', context)
visible.value = false
const arr = {
label: formData.value.name,
value: formData.value.RoutingAddress
}
RATES_OPTIONS.push(arr)
}
const onCancel = context => {
console.log('点击了取消按钮', context)
}
const onCloseBtnClick = context => {
console.log('点击了关闭按钮', context)
}
//
const Role = row => {
visible.value = true
formData.value = {
name: row.label,
RoutingAddress: row.value
}
}
//
const DeleteRole = row => {
console.log('删除学生收费标准', row)
RATES_OPTIONS.splice(RATES_OPTIONS.indexOf(row), 1)
}
//
const onPageChange = () => {
isLoading.value = true
const timerId = setTimeout(() => {
isLoading.value = false
clearInterval(timerId)
}, 300)
}
//
const judge = () => {
if (!route.query.name) {
return true
} else {
return false
}
}
</script>
<style scoped lang="less"></style>

View File

@ -0,0 +1,210 @@
<template>
<div class="back-color">
<div class="form">
<t-form
:data="formData"
reset-type="initial"
colon
@reset="onReset"
@submit="onSubmit"
>
<t-row>
<t-col :span="3">
<t-form-item label="学生姓名" name="name">
<t-input v-model="formData.name"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生部门" name="studentnumber">
<t-input v-model="formData.studentnumber"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生导员" name="counselor">
<t-input v-model="formData.counselor"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生班级" name="grade">
<t-input v-model="formData.grade"></t-input>
</t-form-item>
</t-col>
</t-row>
<t-row style="margin-top: 0.5rem">
<t-col :push="10" :span="2" style="margin-top: 0.2rem">
<div
style="
display: flex;
justify-content: space-between;
width: 8vw;
margin-left: 4.5vw;
"
>
<t-button type="submit">搜索</t-button>
<t-button type="reset">重置</t-button>
</div>
</t-col>
</t-row>
</t-form>
</div>
<div class="table">
<t-table
row-key="id"
:data="tableData"
:columns="columns"
:hover="true"
table-layout="auto"
:pagination="pagination"
:show-header="true"
cell-empty-content="-"
max-height="550"
lazy-load
@row-click="handleRowClick"
@page-change="onPageChange"
:loading="loading"
>
<template #operation="{ row }">
<t-button size="small" @click="onClick(row)">联系该学生导员</t-button>
</template>
</t-table>
</div>
<div class="dialog">
<t-space>
<t-dialog
v-model:visible="visible"
header="联系该学生导员"
width="40%"
:close-on-overlay-click="false"
:on-cancel="onCancel"
:on-close-btn-click="onCloseBtnClick"
:on-confirm="onConfirmAnother"
confirm-btn="联系该导员"
>
<t-space direction="vertical" style="width: 100%">
<t-form :data="formData" reset-type="initial" colon disabled>
<t-form-item label="导员姓名" name="name">
<t-input v-model="dialogData.name"></t-input>
</t-form-item>
<t-form-item label="导员手机号" name="number">
<t-input v-model="dialogData.number"></t-input>
</t-form-item>
</t-form>
</t-space>
</t-dialog>
</t-space>
</div>
</div>
</template>
<script setup lang="jsx">
import { ref, reactive, onMounted } from 'vue'
import {
APIParagraphList,
APIParagraphFind
} from '@/api/receivables-management/management'
//
const formData = reactive({
name: '',
studentnumber: '',
counselor: '',
grade: ''
})
//
const tableData = ref([])
//
const columns = [
{ colKey: 'name', title: '学生姓名' },
{ colKey: 'department', title: '学生院系' },
{ colKey: 'grade', title: '学生班级' },
{ colKey: 'counselor', title: '学生导员' },
{ colKey: 'cellPhone', title: '导员手机号' },
{ colKey: 'money', title: '催款金额' },
{
colKey: 'condition',
title: '还款情况',
cell: (h, { row }) => {
return (
<div>
<t-tag theme='success'>{row.condition}</t-tag>
</div>
)
}
},
{ colKey: 'operation', title: '操作', align: 'center' }
]
//
let pagination = {
defaultCurrent: 1,
defaultPageSize: 10,
total: 50
}
//
const dialogData = reactive({
name: '',
number: ''
})
//
const onPageChange = (Newpage, PreviousPagePrev) => {
loading.value = true
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const loading = ref(false)
//
const handleRowClick = e => {
console.log(e)
}
//
const onReset = () => {
loading.value = true
ParagraphList()
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const onSubmit = async () => {
const res = await APIParagraphFind(formData)
tableData.value = res
pagination.total = res.length
}
//
const ParagraphList = async () => {
const res = await APIParagraphList()
tableData.value = res.data.list
pagination.total = res.data.list.length
}
//
const visible = ref(false)
const onClick = row => {
dialogData.name = row.counselor
dialogData.number = row.cellPhone
visible.value = true
}
//
const onConfirmAnother = () => {
visible.value = false
}
//
const onCancel = () => {}
//
const onCloseBtnClick = () => {}
onMounted(() => {
ParagraphList()
})
</script>
<style lang="less" scoped>
.form {
background-color: #fff;
height: 6rem;
padding-top: 0.5rem;
}
.table {
margin-top: 1rem;
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<div class="back-color">
<div class="linebox">
<lineChart
:categories="categories"
:seriesData="seriesData"
:titleP="title"
:legendList="legendList"
:height="'100%'"
:width="'60rem'"
/>
</div>
<div class="table">
<div>收费日报表</div>
<t-table
:data="tableData"
:columns="columns"
:hover="true"
table-layout="auto"
:pagination="pagination"
:show-header="true"
cell-empty-content="-"
max-height="550"
lazy-load
@row-click="handleRowClick"
@page-change="onPageChange"
:loading="loading"
>
</t-table>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { APIDailyList } from '@/api/receivables-management/management'
import lineChart from '@/components/echarts/line.vue'
import dayjs from 'dayjs'
//
const tableData = ref([])
//
const columns = ref([
{ colKey: 'date', title: '日期' },
{ colKey: 'tuiti', title: '学费' },
{ colKey: 'incidentals', title: '杂费' },
{ colKey: 'materials', title: '书本资料费' },
{ colKey: 'major', title: '校服费' },
{ colKey: 'grade', title: '餐饮费' },
{ colKey: 'tuit', title: '住宿费' },
{ colKey: 'cost', title: '其他费用' },
{ colKey: 'tuition', title: '总计' }
])
//
let pagination = {
defaultCurrent: 1,
defaultPageSize: 10,
total: 50
}
//
const loading = ref(false)
//
const handleRowClick = e => {
console.log(e)
}
//
const onPageChange = (Newpage, PreviousPagePrev) => {
loading.value = true
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//线
const title = ref('收费日报表')
const categories = ref([
'学费',
'杂费',
'书本资料费',
'住宿费',
'其他费用',
'总计'
])
const legendList = ref(['今日费用'])
const seriesData = ref([
{
name: '今日费用',
data: [10, 20, 15, 20, 25, 105],
type: 'line'
}
])
//
const DailyList = async () => {
const res = await APIDailyList()
tableData.value = res.data.list
pagination.total = res.data.list.length
}
onMounted(() => {
DailyList()
})
</script>
<style scoped lang="less">
.linebox {
width: 100%;
height: 100%;
}
.button {
margin-right: 1rem;
margin-left: 3rem;
}
.table {
margin-top: 1rem;
background-color: #fff;
}
</style>

View File

@ -0,0 +1,582 @@
<template>
<div class="back-color">
<div class="table">
<t-table
row-key="id"
:data="tableData"
:columns="columns"
:hover="true"
table-layout="auto"
:pagination="pagination"
:show-header="true"
cell-empty-content="-"
max-height="550"
lazy-load
@page-change="onPageChange"
:loading="loading"
>
</t-table>
</div>
<div>
<div>
<t-select
v-model="value"
placeholder="请选择"
:options="options"
size="medium"
@change="handleChange"
style="
width: 200px;
display: inline-block;
margin-right: 20px;
margin-top: 3rem;
"
/>
</div>
<div style="background-color: #fff; display: flex">
<div ref="chartContainer" style="width: 38rem; height: 30rem"></div>
<div ref="Container" style="width: 38rem; height: 30rem"></div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { APIAnalysisList } from '@/api/receivables-management/management'
import * as echarts from 'echarts'
//
const tableData = ref([])
// loading
const loading = ref(false)
//
const columns = ref([
{ colKey: 'serial-number', title: '序号' },
{ colKey: 'name', title: '学院名称' },
{ colKey: 'studentnumber', title: '学生总数' },
{ colKey: 'department', title: '应缴费人数' },
{ colKey: 'major', title: '实际缴费人数' },
{ colKey: 'grade', title: '应缴总金额' },
{ colKey: 'tuition', title: '未缴费人数' },
{ colKey: 'weigrade', title: '未缴总金额' },
{ colKey: 'shition', title: '实收总金额' },
{ colKey: 'action', title: '操作', align: 'center' }
])
//
let pagination = {
defaultCurrent: 1,
defaultPageSize: 10,
total: 50
}
//
const onPageChange = (Newpage, PreviousPagePrev) => {
loading.value = true
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const AnalysisList = async () => {
const res = await APIAnalysisList()
tableData.value = res.data.list
pagination.total = res.data.list.length
}
//
const chartContainer = ref(null)
const Container = ref(null)
let option = {
title: {
text: '部门缴费人数分析表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}人'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: ['机电工程系', '护理系', '建筑系']
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '应缴费人数',
type: 'line',
data: ['120', '200', '300']
},
{
name: '未缴费人数',
type: 'line',
data: ['80', '120', '200']
}
]
}
let moneypOption = {
title: {
text: '部门缴费分析表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}元'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: ['机电工程系', '护理系', '建筑系', '总计']
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '应缴费',
type: 'line',
data: ['1344000', '2016000', '2016000', '5376000']
},
{
name: '未缴费',
type: 'line',
data: ['672000', '1344000', '168000', '974000']
}
]
}
const eoption = option => {
const chart = echarts.init(chartContainer.value)
chart.setOption(option)
}
const moneyption = option => {
const chart = echarts.init(Container.value)
chart.setOption(option)
}
//
const value = ref('部门')
const options = [
{ label: '部门', value: '部门' },
{ label: '机电工程系', value: '机电工程系' },
{ label: '护理分院', value: '护理分院' },
{ label: '建筑系', value: '建筑系' }
]
const handleChange = value => {
if (value === '部门') {
let option = {
title: {
text: '部门缴费分析表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}人'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: ['机电工程系', '护理系', '建筑系']
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '应缴费人数',
type: 'line',
data: ['120', '200', '300']
},
{
name: '未缴费人数',
type: 'line',
data: ['80', '120', '200']
}
]
}
let moneypOption = {
title: {
text: '部门缴费分析表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}元'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: ['机电工程系', '护理系', '建筑系', '总计']
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '应缴费',
type: 'line',
data: ['1344000', '2016000', '2016000', '5376000']
},
{
name: '未缴费',
type: 'line',
data: ['672000', '1344000', '168000', '974000']
}
]
}
eoption(option)
moneyption(moneypOption)
} else if (value === '机电工程系') {
let option = {
title: {
text: '机电工程系缴费分析表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}人数'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: ['机电一班', '机电二班', '机电三班', '机电四班', '总计']
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '应缴费人数',
type: 'line',
data: [15, 23, 18, 13, 74]
},
{
name: '未缴费人数',
type: 'line',
data: [15, 7, 12, 17, 64]
}
]
}
let moneypOption = {
title: {
text: '机电工程系缴费分析表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}元'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: ['机电一班', '机电二班', '机电三班', '机电四班', '总计']
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '应缴费',
type: 'line',
data: ['1344000', '2016000', '2016000', '5376000']
},
{
name: '未缴费',
type: 'line',
data: ['672000', '1344000', '168000', '974000']
}
]
}
eoption(option)
moneyption(moneypOption)
} else if (value === '护理分院') {
let option = {
title: {
text: '护理分院缴费分析表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}人数'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: [
'护理一班',
'护理二班',
'护理三班',
'护理四班',
'护理五班',
'总计'
]
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '应缴费人数',
type: 'line',
data: [25, 23, 28, 13, 20, 109]
},
{
name: '未缴费人数',
type: 'line',
data: [15, 17, 12, 27, 20, 91]
}
]
}
let moneypOption = {
title: {
text: '护理分院缴费分析表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}元'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: [
'护理一班',
'护理二班',
'护理三班',
'护理四班',
'护理五班',
'总计'
]
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '应缴费',
type: 'line',
data: ['420000', '386400', '470400', '336000', '403200', '1831200']
},
{
name: '未缴费',
type: 'line',
data: ['252000', '285600', '201600', '285600', '403200', '1528800']
}
]
}
eoption(option)
moneyption(moneypOption)
} else if (value === '建筑系') {
let option = {
title: {
text: '建筑系',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}人数'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: ['建筑一班', '建筑二班', '建筑三班', '总计']
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '应缴费人数',
type: 'line',
data: [95, 74, 74, 243]
},
{
name: '未缴费人数',
type: 'line',
data: [25, 6, 26, 63]
}
]
}
let moneypOption = {
title: {
text: '建筑系缴费分析表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c}元'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: ['建筑一班', '建筑二班', '建筑三班', '总计']
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '应缴费',
type: 'line',
data: ['1596000', '1246200', '1246200', '4082400']
},
{
name: '未缴费',
type: 'line',
data: ['420000', '100800', '436800', '1058400']
}
]
}
eoption(option)
moneyption(moneypOption)
}
}
onMounted(() => {
AnalysisList()
eoption(option)
moneyption(moneypOption)
console.log(option.series[0].data)
})
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,145 @@
<template>
<div class="back-color">
<div class="form">
<t-form
:data="formData"
reset-type="initial"
colon
@reset="onReset"
@submit="onSubmit"
>
<t-row>
<t-col :span="3">
<t-form-item label="学生姓名" name="name">
<t-input v-model="formData.name"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生学号" name="studentnumber">
<t-input v-model="formData.studentnumber"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生学院" name="college">
<t-input v-model="formData.college"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="导员姓名" name="tutor">
<t-input v-model="formData.tutor"></t-input>
</t-form-item>
</t-col>
</t-row>
<t-row style="margin-top: 0.5rem">
<t-col :push="10" :span="2" style="margin-top: 0.2rem">
<div
style="
display: flex;
justify-content: space-between;
width: 8vw;
margin-left: 4.5vw;
"
>
<t-button type="submit">搜索</t-button>
<t-button type="reset">重置</t-button>
</div>
</t-col>
</t-row>
</t-form>
</div>
<div class="table">
<t-table
row-key="id"
:data="tableData"
:columns="columns"
:hover="true"
table-layout="auto"
:pagination="pagination"
:show-header="true"
cell-empty-content="-"
max-height="550"
lazy-load
@page-change="onPageChange"
:loading="loading"
>
</t-table>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, reactive } from 'vue'
import {
APIPremiumList,
APIPremiumFind
} from '@/api/receivables-management/management'
//
const tableData = ref([])
//
const formData = reactive({
name: '',
studentnumber: '',
college: '',
tutor: ''
})
//
const columns = ref([
{ colKey: 'serial-number', title: '学生序号', align: 'center' },
{ colKey: 'name', title: '学生姓名', align: 'center' },
{ colKey: 'studentNumber', title: '学号', align: 'center' },
{ colKey: 'gender', title: '性别', align: 'center' },
{ colKey: 'age', title: '年龄', align: 'center' },
{ colKey: 'tuition', title: '退费金额', align: 'center' },
{ colKey: 'enrollmentyear', title: '入学年份', align: 'center' },
{ colKey: 'college', title: '所在学院', align: 'center' },
{ colKey: 'major', title: '所在专业', align: 'center' },
{ colKey: 'grade', title: '所在班级', align: 'center' },
{ colKey: 'tutor', title: '导员姓名', align: 'center' }
])
//
let pagination = {
defaultCurrent: 1,
defaultPageSize: 10,
total: 50
}
//
const loading = ref(false)
//
const PremiumList = async () => {
const res = await APIPremiumList()
tableData.value = res.data.list
pagination.total = res.data.list.length
}
//
const onPageChange = (Newpage, PreviousPagePrev) => {
loading.value = true
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const onReset = () => {
loading.value = true
const timerId = setTimeout(() => {
PremiumList()
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const onSubmit = async () => {
const data = await APIPremiumFind(formData)
tableData.value = data
pagination.total = data.length
}
onMounted(() => {
PremiumList()
})
</script>
<style lang="less" scoped>
.table {
margin-top: 1rem;
}
</style>

View File

@ -0,0 +1,152 @@
<template>
<div class="back-color">
<div class="form">
<t-form
ref="form"
:data="formData"
reset-type="initial"
colon
@reset="onReset"
@submit="onSubmit"
>
<t-row>
<t-col :span="3">
<t-form-item label="学生姓名" name="name">
<t-input v-model="formData.name"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生学号" name="studentnumber">
<t-input v-model="formData.studentnumber"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="所在部门" name="college">
<t-input v-model="formData.college"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学生班级" name="grade">
<t-input v-model="formData.grade"></t-input>
</t-form-item>
</t-col>
</t-row>
<t-row style="margin-top: 0.5rem">
<t-col :span="3"> </t-col>
<t-col :span="3"> </t-col>
<t-col :push="4" :span="2" style="margin-top: 0.2rem">
<div
style="
display: flex;
justify-content: space-between;
width: 8vw;
margin-left: 5vw;
"
>
<t-button type="submit" class="button">搜索</t-button>
<t-button type="reset">重置</t-button>
</div>
</t-col>
</t-row>
</t-form>
</div>
<div class="table">
<t-table
row-key="id"
:data="tableData"
:columns="columns"
:hover="true"
table-layout="auto"
:pagination="pagination"
:show-header="true"
cell-empty-content="-"
max-height="550"
lazy-load
@page-change="onPageChange"
:loading="loading"
>
</t-table>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, reactive } from 'vue'
import {
APIMessageList,
APIMessageFind
} from '@/api/receivables-management/management'
//
const tableData = ref([])
//
const formData = reactive({
name: '',
studentnumber: '',
college: '',
grade: ''
})
//
const columns = ref([
{ colKey: 'serial-number', title: '学生序号', align: 'center' },
{ colKey: 'name', title: '学生姓名', align: 'center' },
{ colKey: 'studentNumber', title: '学号', align: 'center' },
{ colKey: 'gender', title: '性别', align: 'center' },
{ colKey: 'age', title: '年龄', align: 'center' },
{ colKey: 'nativePlace', title: '籍贯', align: 'center' },
{ colKey: 'nation', title: '民族' },
{ colKey: 'enrollmentyear', title: '入学年份', align: 'center' },
{ colKey: 'college', title: '所在学院', align: 'center' },
{ colKey: 'major', title: '所在专业', align: 'center' },
{ colKey: 'grade', title: '所在班级', align: 'center' },
{ colKey: 'tutor', title: '导员姓名', align: 'center' },
{ colKey: 'phone', title: '联系人电话', align: 'center' }
])
//
let pagination = {
defaultCurrent: 1,
defaultPageSize: 10,
total: 50
}
//
const loading = ref(false)
//
const MessageList = async () => {
const res = await APIMessageList()
tableData.value = res.data.list
pagination.total = res.data.list.length
}
//
const onPageChange = (Newpage, PreviousPagePrev) => {
loading.value = true
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const onSubmit = async () => {
const res = await APIMessageFind(formData)
tableData.value = Array.from(res)
pagination.total = res.length
}
//
const onReset = () => {
loading.value = true
MessageList()
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
onMounted(() => {
MessageList()
})
</script>
<style lang="less" scoped>
.form {
background-color: #fff;
height: 6rem;
padding-top: 0.5rem;
}
</style>

View File

@ -0,0 +1,432 @@
<template>
<div class="back-color">
<!-- 表单 -->
<div class="search-form">
<t-form
ref="form"
:data="formData"
reset-type="initial"
colon
@reset="onReset"
@submit="onSubmit"
>
<t-row>
<t-col :span="3">
<t-form-item label="学生姓名" name="name">
<t-input v-model="formData.name"></t-input>
</t-form-item>
</t-col>
<t-col :span="3">
<t-form-item label="学号" name="studentnumber">
<t-input v-model="formData.studentnumber"></t-input>
</t-form-item>
</t-col>
<t-col :push="4" :span="2">
<div
style="
display: flex;
justify-content: space-between;
width: 8vw;
margin-left: 5vw;
"
>
<t-button type="submit">搜索</t-button>
<t-button type="reset">重置</t-button>
</div>
</t-col>
</t-row>
</t-form>
</div>
<!-- 表格 -->
<div>
<div>
<t-row>
<t-col :span="3" :offset="10" style="margin-bottom: 0.5rem">
<t-button theme="default" variant="text" @click="onClick"
>申请助学贷款</t-button
>
</t-col>
</t-row>
</div>
<t-table
row-key="id"
:data="data"
:columns="columns"
table-layout="fixed"
size="medium"
:pagination="pagination"
:show-header="true"
cell-empty-content="-"
max-height="550"
lazy-load
:loading="loading"
@row-click="handleRowClick"
@page-change="onPageChange"
>
</t-table>
</div>
<!-- 图表 -->
<div style="background-color: #fff; margin-top: 4rem; display: flex">
<div ref="chartContainer" style="width: 45rem; height: 35rem"></div>
<div>
<t-select
v-model="value"
placeholder="请选择"
:options="options"
size="medium"
@change="handleChange"
style="width: 200px; display: inline-block; margin-right: 20px"
/>
</div>
</div>
<!-- 弹出框 -->
<div>
<t-space>
<t-dialog
v-model:visible="visible"
header="申请贷款"
width="20%"
:on-cancel="onCancel"
:on-close-btn-click="onCloseBtnClick"
:on-confirm="onConfirmAnother"
:close-on-overlay-click="false"
>
<t-space direction="vertical" style="width: 100%">
<t-space direction="vertical" size="large">
<t-form
ref="form"
:data="formData"
reset-type="initial"
colon
@reset="onReset"
>
<t-form-item label="申请人" name="name">
<t-input v-model="addData.proposer"></t-input>
</t-form-item>
<t-form-item label="学号" name="RoutingAddress">
<t-input v-model="addData.student"></t-input>
</t-form-item>
<t-form-item label="所在部门" name="RoutingAddress">
<t-input v-model="addData.department"></t-input>
</t-form-item>
<t-form-item label="助学金额" name="RoutingAddress">
<t-input v-model="addData.allowance"></t-input>
</t-form-item>
<t-form-item label="是否下款" name="RoutingAddress">
<t-input v-model="addData.loanTerm"></t-input>
</t-form-item>
<t-form-item label="申请时间" name="RoutingAddress">
<t-input v-model="addData.timeofapplication"></t-input>
</t-form-item>
</t-form>
</t-space>
</t-space>
</t-dialog>
</t-space>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import {
APILoansList,
APILoansAdd,
APILoansFind
} from '@/api/receivables-management/management'
import * as echarts from 'echarts'
//
const data = ref([])
//
const formData = ref({
name: '',
studentnumber: ''
})
//
const loading = ref(false)
//
const columns = ref([
{ colKey: 'proposer', title: '申请人', width: '100' },
{ colKey: 'student', title: '学号', width: '100' },
{ colKey: 'department', title: '所在部门', width: '100' },
{ colKey: 'allowance', title: '助学金额', width: '100' },
{ colKey: 'loanTerm', title: '是否下款', width: '100' },
{ colKey: 'timeofapplication', title: '申请时间', width: '100' },
{ colKey: 'status', title: '操作', width: '100' }
])
//
const pagination = ref({
defaultCurrent: 1,
current: 1,
defaultPageSize: 10,
total: 30
})
//
const visible = ref(false)
//
const addData = ref({
proposer: '',
student: '',
department: '',
allowance: '',
loanTerm: '',
timeofapplication: ''
})
//
const options = [
{ label: '年', value: '年' },
{ label: '部门', value: '部门' }
]
//
const value = ref('年')
const handleRowClick = e => {
console.log(e)
}
//
const onPageChange = pageInfo => {
pagination.value.current = pageInfo.current
loading.value = true
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const LoansList = async () => {
const res = await APILoansList()
data.value = res.data.list
pagination.value.total = res.data.list.length
pagination.value.current = 1
}
//
const onReset = () => {
loading.value = true
LoansList()
const timerId = setTimeout(() => {
loading.value = false
clearInterval(timerId)
}, 300)
}
//
const onSubmit = async () => {
console.log('表单提交', formData.value)
if (formData.value.name !== '') {
const res = await APILoansFind(formData.value)
data.value = res
pagination.value.total = res.data.length
pagination.value.current = 1
}
if (formData.value.studentnumber !== '') {
const res = await APILoansFind(formData.value)
data.value = res
pagination.value.total = res.data.length
pagination.value.current = 1
}
}
//
const onClick = context => {
console.log('点击了确认按钮,弹出弹窗', context)
visible.value = true
}
const onConfirmAnother = async context => {
console.log('点击了确认按钮', context)
await APILoansAdd(addData.value)
visible.value = false
}
const onCancel = context => {
console.log('点击了取消按钮', context)
}
const onCloseBtnClick = context => {
console.log('点击了关闭按钮', context)
}
//
const chartContainer = ref(null)
let option = {
title: {
text: '助学贷学生明细表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '助学贷学生:{b}<br/>申请助学贷款:{c}人'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: [
'1月',
'2月',
'3月',
'4月',
'5月',
'6月',
'7月',
'8月',
'9月',
'10月',
'11月',
'12月'
]
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '今年',
type: 'line',
data: [10, 3, 9, 27, 81, 247, 74, 80, 70, 30, 40, 50]
},
{
name: '去年',
type: 'line',
data: [12, 2, 4, 8, 16, 32, 64, 128, 25, 51, 50, 100]
}
]
}
const eoption = option => {
const chart = echarts.init(chartContainer.value)
chart.setOption(option)
}
onMounted(() => {
eoption(option)
})
//
const handleChange = value => {
if (value === '年') {
let option = {
title: {
text: '助学贷学生明细表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '助学贷学生:{b}<br/>申请助学贷款:{c}人'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: [
'1月',
'2月',
'3月',
'4月',
'5月',
'6月',
'7月',
'8月',
'9月',
'10月',
'11月',
'12月'
]
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '今年',
type: 'line',
data: [10, 3, 9, 27, 81, 247, 74, 80, 70, 30, 40, 50]
},
{
name: '去年',
type: 'line',
data: [12, 2, 4, 8, 16, 32, 64, 128, 25, 51, 50, 100]
}
]
}
eoption(option)
} else if (value === '部门') {
let option1 = {
title: {
text: '助学贷学生明细表',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '助学贷学生:{b}<br/>申请助学贷款:{c}人'
},
legend: {
left: 'left'
},
xAxis: {
type: 'category',
name: 'x',
splitLine: { show: false },
data: ['机电工程系', '护理系', '建筑系', '人文系', '社会系']
},
grid: {
left: '0%',
right: '0%',
bottom: '0%',
containLabel: true
},
yAxis: {
type: 'log',
name: 'y',
minorSplitLine: {
show: true
}
},
series: [
{
name: '今年',
type: 'line',
data: [74, 80, 70, 30, 40, 50]
},
{
name: '去年',
type: 'line',
data: [64, 128, 25, 51, 50, 100]
}
]
}
eoption(option1)
}
}
onMounted(() => {
LoansList()
})
</script>
<style lang="less" scoped>
.search-form {
margin-bottom: 1.5rem;
background-color: #fff;
height: 4rem;
padding-top: 1rem;
}
</style>

View File

@ -0,0 +1,257 @@
<template>
<div class="back-color">
<div style="border: 2px solid; width: 640px">
<div class="proposer">
<div class="left">申请人情况</div>
<div class="right">
<div class="up">
<div class="up">
<div>
学号<span
><input v-model="data.studentId" class="span" type="text"
/></span>
</div>
<div>
姓名<span
><input v-model="data.studentName" class="span" type="text"
/></span>
</div>
<div>
性别<span
><input v-model="data.studentSex" class="span" type="text"
/></span>
</div>
<div>
出身年月<span
><input
v-model="data.studentBirthday"
class="span"
type="text"
/></span>
</div>
</div>
<div class="down">
<div>
专业<span
><input v-model="data.studentMajor" class="span" type="text"
/></span>
</div>
<div>
班级<span
><input v-model="data.studentClass" class="span" type="text"
/></span>
</div>
<div>
证号<span
><input v-model="data.studentCard" class="span" type="text"
/></span>
</div>
<div>
身份证号<span
><input v-model="data.studentIdCard" class="span" type="text"
/></span>
</div>
</div>
</div>
<div class="below">
<div>
家庭住址
<span
><input v-model="data.studentAddress" class="span1" type="text"
/></span>
</div>
<div>
邮政编码
<span
><input v-model="data.studentZip" class="span1" type="text"
/></span>
</div>
<div>
联系电话
<span
><input v-model="data.studentPhone" class="span1" type="text"
/></span>
</div>
<div>
年缴学费
<span
><input v-model="data.studentFee" class="span1" type="text"
/></span>
</div>
</div>
</div>
</div>
<div class="family">
<div>
<div class="family" style="border: 0.5px solid">家庭情况</div>
</div>
<div>
<div style="border: 0.5px solid">1</div>
</div>
</div>
<div class="allowance">
<div>
<div class="allowance" style="border: 0.5px solid">减免申请</div>
</div>
<div>
<div>2</div>
</div>
</div>
<div class="counselor">
<div>
<div class="counselor" style="border: 0.5px solid">辅导员意见</div>
</div>
<div>
<div>3</div>
</div>
</div>
<div class="production">
<div>
<div class="production" style="border: 0.5px solid">学工部意见</div>
</div>
<div>
<div>1</div>
</div>
</div>
<div class="competent">
<div>
<div class="competent" style="border: 0.5px solid">
主管院长审批意见
</div>
</div>
<div>
<div>4</div>
</div>
</div>
<div class="standby">
<div style="border: 0.5px solid">备注</div>
</div>
</div>
<div style="display: flex; justify-content: flex-end; margin-top: 1rem">
<t-button theme="default" variant="text" @click="handleClick"
>填写完毕立刻生低档</t-button
>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
const Router = useRouter()
const data = ref({
//
studentId: '',
//
studentName: '',
//
studentSex: '',
//
studentBirthday: '',
//
studentMajor: '',
//
studentClass: '',
//
studentCard: '',
//
studentIdCard: '',
//
studentAddress: '',
//
studentZip: '',
//
studentPhone: '',
//
studentFee: '',
//
routers: '1'
})
const handleClick = () => {
Router.push({
path: '/billCollected'
})
}
</script>
<style lang="less" scoped>
.proposer {
display: flex;
height: 4.5rem;
width: 100%;
.left {
border: 0.5px solid;
width: 3rem;
height: 4.5rem;
padding-top: 1rem;
}
.right {
.up {
.up {
display: flex;
justify-content: space-between;
}
.down {
display: flex;
justify-content: space-between;
}
}
.below {
display: flex;
.jia {
width: 8rem;
height: 2rem;
}
.bian {
width: 3rem;
height: 1.5srem;
}
.hua {
width: 2rem;
height: 1.5rem;
}
.nian {
width: 2rem;
height: 1.5rem;
}
}
}
}
.family {
height: 10rem;
display: flex;
width: 3rem;
}
.allowance {
height: 10rem;
display: flex;
width: 3rem;
}
.counselor {
height: 10rem;
display: flex;
width: 3rem;
}
.production {
height: 10rem;
display: flex;
width: 3rem;
}
.competent {
height: 10rem;
display: flex;
width: 3rem;
}
.span {
width: 7rem;
height: 1.5rem;
}
.span1 {
width: 5rem;
height: 1.5rem;
}
input {
border-style: none;
background-color: #f5f7fb;
}
</style>

View File

@ -0,0 +1,438 @@
<template>
<div class="back-color">
<t-layout style="height: 90%; background-color: #f5f7fb">
<t-header class="scarch-box">
<t-form
ref="form"
:data="studentData"
label-width="calc(2em + 40px)"
layout="inline"
class="scarch-from"
colon
@reset="onReset"
@submit="onSubmit"
>
<div style="margin-left: 0.5rem">
<t-form-item label="姓名" name="name">
<t-input v-model="studentData.name"></t-input>
</t-form-item>
<t-form-item label="学号" name="studentId">
<t-input v-model="studentData.studentId"></t-input>
</t-form-item>
</div>
<t-form-item style="margin-right: 1rem">
<t-button theme="primary" type="submit">查询</t-button>
<t-button
theme="default"
variant="base"
type="reset"
style="margin-left: 1rem"
>重置</t-button
>
</t-form-item>
</t-form>
</t-header>
<t-content class="table-box">
<div class="table-header">
<div>
<h4 style="font-size: 110%">学生列表</h4>
</div>
<div>
<t-button theme="primary" size="small" style="margin-right:0rem" @click="onAddSubmit">
<template #icon><add-icon /></template>
增加学员信息
</t-button>
<t-button
shape="circle"
theme="primary"
@click="refresh"
style="margin-left: 0.8rem"
>
<template #icon><load-icon /></template>
</t-button>
</div>
</div>
<t-base-table
rowKey="Id"
:data="studentList"
:columns="studentColumns"
:hover="true"
:pagination="pagination"
cellEmptyContent="-"
lazy-load
@row-click="handleRowClick"
@page-change="onPageChange"
:loading="loading"
max-height="550"
>
<template #operation="{ row }">
<t-button
theme="default"
variant="text"
size="small"
@click="Modify(row)"
>修改</t-button
>
<t-popconfirm content="确认删除吗" @confirm="Delete(row)">
<t-button theme="default" variant="text" size="small"
>删除</t-button
>
</t-popconfirm>
</template>
</t-base-table>
</t-content>
</t-layout>
<t-space>
<t-dialog
v-model:visible="visible"
header="学生变动处理"
width="40%"
:confirm-on-enter="true"
:on-cancel="onCancel"
:on-esc-keydown="onEscKeydown"
:on-close-btn-click="onCloseBtnClick"
:on-overlay-click="onOverlayClick"
:on-close="close"
:on-confirm="onConfirmAnother"
ref="postForm"
>
<t-space direction="vertical" style="width: 100%">
<div>
<t-form
ref="form"
:data="dialogData"
reset-type="initial"
colon
@reset="onReset"
>
<t-form-item label="姓名" name="name">
<t-input v-model="dialogData.name"></t-input>
</t-form-item>
<t-form-item label="性别" name="gender">
<t-input v-model="dialogData.gender"></t-input>
</t-form-item>
<t-form-item label="学号" name="studentId">
<t-input v-model="dialogData.studentId"></t-input>
</t-form-item>
<t-form-item label="系院" name="department">
<t-input v-model="dialogData.department"></t-input>
</t-form-item>
<t-form-item label="专业" name="major">
<t-input v-model="dialogData.major"></t-input>
</t-form-item>
<t-form-item label="班级" name="classes">
<t-input v-model="dialogData.classes"></t-input>
</t-form-item>
<t-form-item
label="状态"
name="status"
:span="12"
style="width: 16rem; margin-bottom: 0.5rem"
>
<t-select
v-model="dialogData.status"
clearable
placeholder="请选择状态"
>
<t-option
v-for="item in status"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</t-select>
</t-form-item>
</t-form>
</div>
</t-space>
</t-dialog>
</t-space>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from "vue";
import { getList, getStudents, updateStudent } from "@/api/students";
// import {reqStudent} from "@/api/students";
import { MessagePlugin } from "tdesign-vue-next";
import { useRouter } from "vue-router";
import { AddIcon, LoadIcon } from "tdesign-icons-vue-next";
// import { reqStudent } from "@/api/students";
const router = useRouter();
const studentData = ref({
Id: "",
name: "",
gender: "",
studentId: "",
department: "",
major: "",
classes: "",
status: "",
});
//
const dialogData = ref({
name: "",
gender: "",
studentId: "",
department: "",
major: "",
classes: "",
status: "",
});
const visible = ref(false);
const studentList = ref([]);
const studentColumns = ref([
{
colKey: "Id",
title: "序号",
width: "100",
},
{
colKey: "name",
title: "姓名",
align: "center",
width: "100",
},
{
colKey: "gender",
title: "性别",
align: "center",
width: "100",
},
{
colKey: "studentId",
title: "学号",
align: "center",
width: "150",
},
{
colKey: "department",
title: "系院",
align: "center",
width: "150",
},
{
colKey: "major",
title: "专业",
align: "center",
width: "150",
},
{
colKey: "classes",
title: "班级",
align: "center",
width: "150",
},
{
colKey: "status",
title: "状态",
align: "center",
width: "150",
},
{
colKey: "operation",
title: "操作",
align: "center",
width: "150",
},
]);
const pagination = ref({
defaultCurrent: 1,
defaultPageSize: 10,
total: 0,
});
//
const onSubmit = async () => {
if (
studentData.Id ||
studentData.name ||
studentData.gender ||
studentData.studentId ||
studentData.department ||
studentData.major ||
studentData.classes ||
studentData.status
) {
const res = await getStudents(studentData);
// console.log(res);
studentList.value = Array.from(res);
pagination.total = res.length;
} else {
alert("请填写完整信息");
}
};
//
const onReset = () => {
TableData();
};
const status = ref([
{ label: "休学", value: 0 },
{ label: "退学", value: 1 },
{ label: "复学", value: 2 },
]);
//
const TableData = async () => {
const res = await getList();
// console.log(res);
studentList.value = res.data.list;
pagination.value.total = res.data.list.length;
};
onMounted(() => {
TableData();
});
//
const Modify = (row) => {
console.log("点击了确认按钮,弹出弹窗", row);
visible.value = true;
dialogData.value = {
...row
};
};
const onAddSubmit = async ({ validateResult, firstError }) => {
if (validateResult === true) {
await TableData.addStockList(dialogData.value);
getNewTable();
MessagePlugin.success("提交成功");
visible.value = false;
} else {
console.log("Validate Errors: ", firstError, validateResult);
}
};
// const onConfirmAnother = async () => {
// console.log("", );
// visible.value = false;
// await updateStudent(dialogData.value)
// };
const onConfirmAnother = async () => {
// const index = studentList.value.findIndex((item)=> item.Id === .Id)
// await aaa(dialogData.value)
// TableData()
// if (index !== -1) {
// studentList.value.splice(index,dialogData.value)
// }else{
// console.log(11111);
// }
// console.log("" ,studentId);
// //
// const studentId = dialogData.value.studentId;
// //
// try {
// const response = await updateStudent({ ...dialogData.value, studentId });
// //
// if (response) {
// //
// const index = studentList.value.findIndex(
// (stu) => stu.studentId === studentId
// );
// if (index !== -1) {
// studentList.value.splice(index, 1, dialogData.value);
// }
// MessagePlugin.success("");
// } else {
// MessagePlugin.error(response.message || "");
// }
// } catch (error) {
// console.error("", error);
// MessagePlugin.error("");
// }
//
visible.value = false;
};
const Delete = async (row) => {
try {
// APIdeleteStudentID
const response = await deleteStudent(row.studentId);
if (response.success) {
//
const index = studentList.value.findIndex((stu) => stu.studentId === row.studentId);
if (index !== -1) {
studentList.value.splice(index, 1);
}
pagination.total -= 1;
//
MessagePlugin.success('学生信息删除成功');
} else {
//
MessagePlugin.error(response.message || '学生信息删除失败');
}
} catch (error) {
console.error('删除学生信息时发生错误', error);
MessagePlugin.error('学生信息删除失败');
}
};
const close = (context) => {
console.log("关闭弹窗点击关闭按钮、按下ESC、点击蒙层等触发", context);
};
const onCancel = (context) => {
console.log("点击了取消按钮", context);
};
const onEscKeydown = (context) => {
console.log("按下了ESC", context);
};
const onCloseBtnClick = (context) => {
console.log("点击了关闭按钮", context);
};
const onOverlayClick = (context) => {
console.log("点击了蒙层", context);
};
</script>
<style lang="less" scoped>
.scarch-box {
width: 100%;
background-color: @base-white-color;
margin-bottom: 2rem;
.scarch-from {
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.table-box {
height: 42rem;
background-color: @base-white-color;
padding: 1rem;
padding-top: 0;
.table-header {
height: 3rem;
display: flex;
justify-content: space-between;
align-items: center;
}
}
:deep(.t-form__controls-content) {
justify-content: space-between;
}
</style>

View File

@ -1,23 +1,44 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from "vue-router";
import HomeView from '../views/HomeView.vue' import FinanceBillManage from "./modules/financeBillManage";
import ReceivablesManagement from "./modules/receivablesManagement";
import StudentManage from "./modules/studentManage";
import Login from "@/pages/login/index.vue";
import Password from "@/pages/password/index.vue";
import Layout from "@/layout/index.vue";
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: [ routes: [
{ {
path: '/', path: "/",
name: 'home', redirect: "/home",
component: HomeView meta: { title: "首页", name: "home" },
component: Layout,
children: [
{
path: "/home",
name: "home",
component: () => import("@/pages/home/index.vue"),
meta: {
title: "首页",
},
},
],
}, },
{ {
path: '/about', path: "/login",
name: 'about', name: "login",
// route level code-splitting component: Login,
// this generates a separate chunk (About.[hash].js) for this route },
// which is lazy-loaded when the route is visited. {
component: () => import('../views/AboutView.vue') path: "/password-reset",
} name: "password",
] component: Password,
}) },
...FinanceBillManage,
...ReceivablesManagement,
...StudentManage,
],
});
export default router export default router;

View File

@ -0,0 +1,95 @@
import Layout from "@/layout/index.vue";
import BillStockURL from "@/pages/finance-bill-manage/billStock.vue";
import BillCancelURL from "@/pages/finance-bill-manage/billCancel.vue";
import BillReceiptURL from "@/pages/finance-bill-manage/billReceipt.vue";
import BillQuitneckURL from "@/pages/finance-bill-manage/billQuitneck.vue";
import BillBreakagekURL from "@/pages/finance-bill-manage/billBreakage.vue";
import BillDestroyURL from "@/pages/finance-bill-manage/billDestroy.vue";
import DetailReportURL from "@/pages/finance-bill-manage/detailReport.vue";
import BillDrawURL from "@/pages/finance-bill-manage/billDraw.vue";
import dragUrl from "@/pages/finance-bill-manage/drag.vue";
const financeBillManage = [
{
path: "/Bill",
name: "bill",
component: Layout,
meta: { title: "票据管理", name: "resource" },
children: [
{
path: "BillStock",
name: "billStock",
component: BillStockURL,
meta: {
title: "票据上传",
},
},
{
path: "BillCancel",
name: "billCancel",
component: BillCancelURL,
meta: {
title: "票据退库",
},
},
{
path: "BillReceipt",
name: "billReceipt",
component: BillReceiptURL,
meta: {
title: "票据领用",
},
},
{
path: "BillQuitneck",
name: "billQuitneck",
component: BillQuitneckURL,
meta: {
title: "票据退领",
},
},
{
path: "BillBreakagek",
name: "billBreakagek",
component: BillBreakagekURL,
meta: {
title: "票据报损",
},
},
{
path: "BillDestroy",
name: "billDestroy",
component: BillDestroyURL,
meta: {
title: "票据核销",
},
},
{
path: "DetailReport",
name: "detailReport",
component: DetailReportURL,
meta: {
title: "报表明细",
},
},
{
path: "BillDraw",
name: "billDraw",
component: BillDrawURL,
meta: {
title: "报表明细",
},
},
{
path: "drag",
name: "drag",
component: dragUrl,
meta: {
title: "拖拽效果",
},
},
],
},
];
export default financeBillManage;

View File

@ -0,0 +1,93 @@
import Layout from "@/layout/index.vue";
const ReceivablesManagement = [
{
path: "/accounts",
meta: { title: "应收款管理", name: "accounts" },
component: Layout,
children: [
{
path: "/accounts",
name: "Accounts",
component: () => import("@/pages/receivables-management/accountReceivable.vue"),
meta: {
title: "应收款管理",
},
},
{
path: "/billCollected",
name: "BillCollected",
component: () => import("@/pages/receivables-management/billCollected.vue"),
meta: { title: "票据收款", },
},
{
path: "/bill-bill",
name: "BillBill",
component: () => import("@/pages/receivables-management/Bill.vue"),
meta: { title: "票据", hidden: false },
},
{
path: "/student-loan",
name: "StudentLoan",
component: () => import("@/pages/receivables-management/studentLoan.vue"),
meta: { title: "助学贷款", },
},
{
path: "/waivar-form",
name: "WaivarForm",
component: () => import("@/pages/receivables-management/waiverForm.vue"),
meta: { title: "学生减免单", hidden: false },
},
{
path: "/daily",
name: "Daily",
component: () => import("@/pages/receivables-management/daily.vue"),
meta: { title: "收费日报及收费明细", },
},
{
path: "/charge-schedule",
name: "ChargeSchedule",
component: () => import("@/pages/receivables-management/chargeSchedule.vue"),
meta: { title: "学生催款单", },
},
{
path: "/faculty-analysis",
name: "FacultyAnalysis",
component: () => import("@/pages/receivables-management/facultyAnalysis.vue"),
meta: { title: "部门分析表", },
},
{
path: "/student-information",
name: "StudentInformation",
component: () => import("@/pages/receivables-management/studentInformation.vue"),
meta: { title: "学生信息统计表", },
},
{
path: "/mitigate",
name: "Mitigate",
component: () => import("@/pages/receivables-management/Mitigate.vue"),
meta: { title: "学生减免明细表", },
},
{
path: "/return-premium",
name: "ReturnPremium",
component: () => import("@/pages/receivables-management/returnPremium.vue"),
meta: { title: "学生退费明细表", },
},
{
path: "/rrrearage",
name: "Arrearage",
component: () => import("@/pages/receivables-management/Arrearage.vue"),
meta: { title: "学生欠费明细表", },
},
{
path: "/shi-yan",
name: "Shiyan",
component: () => import("@/pages/receivables-management/ShiYan.vue"),
meta: { title: "实验", },
}
],
},
];
export default ReceivablesManagement;

View File

@ -0,0 +1,24 @@
import Layout from "@/layout/index.vue";
// import studentURL from "@/pages/students/student";
import studentURL from "@/pages/students/student.vue";
const financeBillManage = [
{
path: "/Student",
name: "student",
component: Layout,
meta: { title: "学生", name: "resource" },
children: [
{
path: "/Students",
name: "students",
component: studentURL,
meta: {
title: "学生管理",
},
},
],
},
];
export default financeBillManage;

View File

@ -0,0 +1,36 @@
import { defineStore } from "pinia";
import { reqBreakageList } from "@/api/finance-bill-manage/breakageList";
export const useBreakage = defineStore("breakageList", {
state: () => {
return {
breakageList: [],
destroyList: [],
};
},
actions: {
async getBreakageList() {
let { data } = await reqBreakageList();
this.breakageList = data.list;
return this.breakageList;
},
addBreakageList(arr) {
const index = this.breakageList.findIndex((item) => item.id === arr.id);
if (index !== -1) {
this.breakageList[index] = arr;
} else {
arr.id = new Date().getTime();
this.breakageList.unshift(arr);
localStorage.setItem("breakageList", JSON.stringify(this.breakageList));
}
this.destroyList.push(arr);
localStorage.setItem("destroyList", JSON.stringify(this.breakageList));
return this.breakageList;
},
deleteBreakageList(item) {
let arr = this.breakageList.filter((i) => i.id !== item.id);
this.breakageList = arr;
},
},
persist: true,
});

28
src/stores/billCancel.js Normal file
View File

@ -0,0 +1,28 @@
import { defineStore } from "pinia";
import { reqCancelList } from "@/api/finance-bill-manage/cancelList";
export const useCancel = defineStore("CancelList", {
state: () => {
return {
cancelList: [],
};
},
actions: {
async getCancelList() {
let { data } = await reqCancelList();
this.cancelList = data.list;
return this.cancelList;
},
editApprovalStatus(arr) {
const index = this.cancelList.findIndex((item) => item.id === arr.row.id);
if (index !== -1) {
this.cancelList[index] = arr.row;
}
},
deleteCancelList(item) {
let arr = this.cancelList.filter((i) => i.id !== item.id);
this.cancelList = arr;
},
},
persist: true,
});

35
src/stores/billDestroy.js Normal file
View File

@ -0,0 +1,35 @@
import { defineStore } from "pinia";
export const useDestroy = defineStore("destroyList", {
state: () => {
return {
destroyList: [],
};
},
actions: {
async getDestroyList() {
const storedData = localStorage.getItem("breakageList");
if (storedData) {
const parsedData = JSON.parse(storedData);
this.destroyList = parsedData.destroyList;
}
return this.destroyList;
},
auditDestroyList(item) {
const storedData = localStorage.getItem("breakageList");
if (storedData) {
const parsedData = JSON.parse(storedData);
parsedData.destroyList = parsedData.destroyList.filter((i) => i.id !== item.id);
parsedData.breakageList = parsedData.breakageList.map((i) => {
if (i.id === item.id) {
return { ...i, breakStatus: item.breakStatus }; // 返回更新后的对象
}
return i; // 保持其他项不变
});
localStorage.setItem("breakageList", JSON.stringify(parsedData));
this.destroyList = parsedData.destroyList; // 更新store中的destroyList状态
}
},
},
persist: true,
});

View File

@ -0,0 +1,56 @@
import { defineStore } from "pinia";
export const useQuitneckList = defineStore("QuitneckList", {
state: () => {
return {
sdyList: [],
ycyList: [],
lczList: [],
lxyList: [],
};
},
actions: {
getQuitneckList(name) {
this.sdyList = [];
this.ycyList = [];
this.lczList = [];
this.lxyList = [];
const allArr = JSON.parse(
localStorage.getItem("ReceiptList")
).quitneckList;
if (name === "孙东宇") {
allArr.forEach((item) => {
if (item.proposer === "孙东宇") {
this.sdyList.push(item);
}
});
return this.sdyList;
}
if (name === "杨春宇") {
allArr.forEach((item) => {
if (item.proposer === "杨春宇") {
this.ycyList.push(item);
}
});
return this.ycyList;
}
if (name === "吕才卓") {
allArr.forEach((item) => {
if (item.proposer === "吕才卓") {
this.lczList.push(item);
}
});
return this.lczList;
}
if (name === "刘欣宇") {
allArr.forEach((item) => {
if (item.proposer === "刘欣宇") {
this.lxyList.push(item);
}
});
return this.lxyList;
}
},
},
persist: true,
});

33
src/stores/billReceipt.js Normal file
View File

@ -0,0 +1,33 @@
import { defineStore } from "pinia";
import { reqPersonName, reqReceiptList } from "@/api/finance-bill-manage/receiptList";
export const useReceiptList = defineStore("ReceiptList", {
state: () => {
return {
personName: [],
receiptList: [],
quitneckList: [],
};
},
actions: {
async getPersonNameList() {
const { data } = await reqPersonName();
this.personName = data;
return this.personName;
},
async getReceiptList(obj) {
const { data } = await reqReceiptList(obj);
this.receiptList = data;
return this.receiptList;
},
async getquitneckNum(obj) {
const index = this.receiptList.findIndex((item) => item.id === obj.id);
if (index !== -1) {
this.receiptList[index].receiptNum = this.receiptList[index].receiptNum - obj.quitneckNum;
}
this.quitneckList.push(obj);
},
},
persist: true,
});

33
src/stores/billStock.js Normal file
View File

@ -0,0 +1,33 @@
import { defineStore } from "pinia";
import { reqStockList } from "@/api/finance-bill-manage/stockList";
export const useStock = defineStore("menuManagement", {
state: () => {
return {
stockList: [],
};
},
actions: {
async getStockList() {
let { data } = await reqStockList();
this.stockList = data.list;
return this.stockList;
},
addStockList(arr) {
const index = this.stockList.findIndex((item) => item.id === arr.id);
if (index !== -1) {
this.stockList[index] = arr;
} else {
arr.id = new Date().getTime();
this.stockList.unshift(arr);
localStorage.setItem("stockList", JSON.stringify(this.stockList));
}
return this.stockList;
},
deleteStockList(item) {
let arr = this.stockList.filter((i) => i.id !== item.id);
this.stockList = arr;
},
},
persist: true,
});

9
src/stores/index.js Normal file
View File

@ -0,0 +1,9 @@
import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
export { store };
export default store;

211
src/style/index.css Normal file
View File

@ -0,0 +1,211 @@
/**
* ENGINE
* v0.2 | 20150615
* License: none (public domain)
*/
*,
*:after,
*:before {
box-sizing: border-box;
outline: none;
}
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
font: inherit;
font-size: 100%;
margin: 0;
padding: 0;
vertical-align: baseline;
border: 0;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
q:before,
blockquote:after,
q:after {
content: '';
content: none;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
table {
border-spacing: 0;
border-collapse: collapse;
}
input,
textarea,
button {
font-family: inhert;
font-size: inherit;
color: inherit;
}
select {
text-indent: 0.01px;
text-overflow: '';
border: 0;
border-radius: 0;
-webkit-appearance: none;
-moz-appearance: none;
}
select::-ms-expand {
display: none;
}
code,
pre {
font-family: monospace, monospace;
font-size: 1em;
}
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
width: 10px;
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
border-radius: 8px;
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: #e5e5e5;
}
.t-default-menu__inner .t-menu--scroll {
background-image: linear-gradient(#fff, rgba(146, 146, 255, 0.2));
}
.back-color {
background-color: #f5f7fb;
padding: 16px 24px;
height: calc(96vh - 64px);
overflow-y: auto;
overflow-x: hidden;
}
a,
a:link,
a:visited,
a:hover,
a:active {
text-decoration: none;
}
.t-button--variant-text .t-button__text {
color: #0052d9;
}
.t-button--variant-text .t-button__text:hover {
color: #8799a3;
}
.t-is-disabled .t-button__text {
color: #d3d3d3 !important;
}
.form-item-width {
width: 100%;
}

60
src/style/index.less Normal file
View File

@ -0,0 +1,60 @@
// 引入清除模式样式
@import './reset.less';
@import './variables.less';
// 滚动条外观样式
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
width: 10px;
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
border-radius: 8px;
box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: @base-scrollbar-color;
}
.t-default-menu__inner .t-menu--scroll {
background-image: linear-gradient(#fff, rgba(146, 146, 255, 0.2));
}
// 主体背景颜色以及大小
.back-color {
background-color: #f5f7fb;
padding: 16px 24px;
height: calc(96vh - 64px);
overflow-y: auto;
overflow-x: hidden;
}
// 去除a标签默认样式
a,
a:link,
a:visited,
a:hover,
a:active {
text-decoration: none;
}
// 改变文字按钮的颜色
.t-button--variant-text .t-button__text {
color: @base-text-color;
}
// 改变文字按钮移入的颜色
.t-button--variant-text .t-button__text:hover {
color: #8799a3;
}
// 禁用的颜色
.t-is-disabled .t-button__text{
color: #d3d3d3 !important;
}
// 查询框宽度
.form-item-width {
width: 100%;
}

View File

@ -168,16 +168,3 @@ pre {
font-family: monospace, monospace; font-family: monospace, monospace;
font-size: 1em; font-size: 1em;
} }
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
font-weight: normal;
}
a,
.green {
text-decoration: none;
color: hsl(160, 100%, 37%);
transition: 0.4s;
padding: 3px;
}

View File

@ -186,17 +186,3 @@
font-family: monospace, monospace; font-family: monospace, monospace;
font-size: 1em; font-size: 1em;
} }
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
font-weight: normal;
}
a,
.green {
text-decoration: none;
color: hsla(160, 100%, 37%, 1);
transition: 0.4s;
padding: 3px;
}

14
src/style/variables.less Normal file
View File

@ -0,0 +1,14 @@
// 设置less全局变量
// 左侧的菜单的宽度
@base-menu-width: 260px;
// 左侧菜单的背景颜色
@base-menu-background: rgb(229, 229, 229);
// 顶部导航高度b
@base-tabbar-height: 50px;
// 公用颜色
@base-white-color: #fff;
// text按钮的颜色
@base-text-color: #0052d9;
// 滚动条的颜色
@base-scrollbar-color: rgb(229, 229, 229);

24
src/utils/excel.js Normal file
View File

@ -0,0 +1,24 @@
import ExcelJS from "exceljs";
import saveAs from "file-saver"; // 引入FileSaver.js以使用saveAs函数
const ExcelUtils = (title, titleFile, columns, addRow) => {
// 创建一个新的工作簿
const workbook = new ExcelJS.Workbook();
// 添加一个新的工作表
const worksheet = workbook.addWorksheet(title);
// 添加表头
worksheet.columns = columns;
// 添加数据行
for (const row of addRow) {
worksheet.addRow(row);
}
// 写入文件并下载
workbook.xlsx.writeBuffer().then((buffer) => {
const blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
saveAs(blob, `${titleFile}.xlsx`);
});
};
export { ExcelUtils };

20
src/utils/pdf.js Normal file
View File

@ -0,0 +1,20 @@
import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";
pdfMake.vfs = pdfFonts.pdfMake.vfs;
export const exportToPDF = (content) => {
const docDefinition = {
pageSize: "A4",
pageMargins: [40, 70, 40, 90],
content: content,
styles: {
header: { fontSize: 16, bold: true },
label: { fontSize: 12, bold: true },
value: { fontSize: 12 },
tableHeader: { fontSize: 12, bold: true, color: "#666" },
footer: { fontSize: 10, italics: true },
},
};
pdfMake.createPdf(docDefinition).download("output.pdf");
};

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

@ -0,0 +1,72 @@
// 进行axios二次封装使用请求与响应拦截器
import axios from "axios";
import { MessagePlugin } from "tdesign-vue-next";
// import { refreshToken } from '@/apis/token'
// import { useTokenStore } from '@/stores/index'
// 第一步:利用axios对象的create方法去创建axios实例(其他的配置:基础的路径、超时的时间)
const request = axios.create({
baseURL: "/", // 基础路径上会携带/api
timeout: 5000, // 超时的时间的设置
});
// 第二步axios实例添加请求与响应拦截器
request.interceptors.request.use((config) => {
// config配置对象headers属性请求头经常给服务器端携带公共参数
// 返回配置对象
// const { token } = useTokenStore()
// if (token) {
// config.headers.Authorization = `Bearer ${token}`
// }
return config;
});
// 第三步axios响应拦截器
request.interceptors.response.use(
(response) => {
// 成功回调
// 简化数据
return response.data;
},
async (error) => {
// 失败回调处理http网络错误的
// 定义一个变量:存储网络错误信息
let message = "";
const { status } = error.response;
// http状态码
switch (status) {
case 401:
// try {
// const tokenStore = useTokenStore()
// const refreshedTokenData = await refreshToken(tokenStore.refreshToken)
// if (refreshedTokenData && refreshedTokenData.data.token) {
// tokenStore.setToken(refreshedTokenData.data.token)
// const originalRequest = error.config
// originalRequest.headers.Authorization = `Bearer ${refreshedTokenData.data.token}`
// return request(originalRequest)
// }
// } catch (error) {
// const tokenStore = useTokenStore()
// tokenStore.clearToken()
// useRouter().push('/login')
// }
break;
case 403:
message = "无权访问";
break;
case 404:
message = "请求地址错误";
break;
case 500:
message = "服务器出现问题";
break;
default:
message = "网络出现问题";
break;
}
MessagePlugin.error(message);
return Promise.reject(error);
}
);
// 对外暴露
export default request;

51
src/utils/requestMock.js Normal file
View File

@ -0,0 +1,51 @@
// 进行axios二次封装使用请求与响应拦截器
import axios from "axios";
import { MessagePlugin } from "tdesign-vue-next";
// 第一步:利用axios对象的create方法去创建axios实例(其他的配置:基础的路径、超时的时间)
const request = axios.create({
baseURL: "/api", // 基础路径上会携带/api
timeout: 5000, // 超时的时间的设置
});
// 第二步axios实例添加请求与响应拦截器
request.interceptors.request.use((config) => {
return config;
});
// 第三步axios响应拦截器
request.interceptors.response.use(
(response) => {
// 成功回调
// 简化数据
return response.data;
},
async (error) => {
// 失败回调处理http网络错误的
// 定义一个变量:存储网络错误信息
let message = "";
const { status } = error.response;
// http状态码
switch (status) {
case 401:
message = "TOKEN过期";
break;
case 403:
message = "无权访问";
break;
case 404:
message = "请求地址错误";
break;
case 500:
message = "服务器出现问题";
break;
default:
message = "网络出现问题";
break;
}
MessagePlugin.error(message);
return Promise.reject(error);
}
);
// 对外暴露
export default request;

View File

@ -1,34 +1,45 @@
import { fileURLToPath, URL } from 'node:url' import { fileURLToPath, URL } from "node:url";
import path from "path";
import { defineConfig } from 'vite' import { defineConfig } from "vite";
import vue from '@vitejs/plugin-vue' import vue from "@vitejs/plugin-vue";
import vueJsx from '@vitejs/plugin-vue-jsx' import vueJsx from "@vitejs/plugin-vue-jsx";
import { viteMockServe } from 'vite-plugin-mock' import { viteMockServe } from "vite-plugin-mock";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
server: {
proxy: {
"/api": {
target: "http://192.168.1.2:8080",
changeOrigin: true,
},
},
},
plugins: [ plugins: [
vue(), vue(),
vueJsx(), vueJsx(),
viteMockServe({ viteMockServe({
mockPath: 'mock', mockPath: "mock",
enable: true enable: true,
}) }),
], ],
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)) "@": fileURLToPath(new URL("./src", import.meta.url)),
} },
}, },
css: { css: {
preprocessorOptions: { preprocessorOptions: {
less: { less: {
modifyVars: { modifyVars: {
hack: `true; @import (reference) "${path.resolve('src/style/variables.less')}";` hack: `true; @import (reference) "${path.resolve(
"src/style/variables.less"
)}";`,
}, },
math: 'strict', math: "strict",
javascriptEnabled: true javascriptEnabled: true,
} },
} },
} },
}) });