This commit is contained in:
吕才卓 2024-04-09 18:05:48 +08:00
commit 74cebfe7d4
27 changed files with 1706 additions and 33 deletions

View File

@ -13,6 +13,20 @@ const data = Mock.mock({
}
]
})
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': '@date("yyyy-MM-dd")',
}
]
})
export default [
{
url: '/get-sdy-managment-list',
@ -58,5 +72,38 @@ export default [
code: 200,
}
}
},
// 借款管理
{
url: '/get-sdy-loan-list',
method: 'get',
response: () => {
return {
code: 200,
data: loans
}
}
},
// 添加借款人
{
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
}
}
},
]

View File

@ -8,7 +8,6 @@ const StockList = Mock.mock({
billserial: "@integer(100000000,199999999)1",
billType: "@integer(0,4)",
stockNum: "@integer(1,2)",
unit: "@cword(张本,1)",
stockDate: "@date",
operator: "@cname",
remark: " @integer(10000000000,19999999999)",
@ -182,6 +181,21 @@ const breakageList = Mock.mock({
},
],
});
//
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 [
{
@ -252,4 +266,14 @@ export default [
};
},
},
{
url: "/api/detailReportList",
method: "get",
response: () => {
return {
code: 200,
data: detailReportList,
};
},
},
];

28
package-lock.json generated
View File

@ -10,6 +10,7 @@
"dependencies": {
"axios": "^1.6.8",
"dayjs": "^1.11.10",
"echarts": "^5.5.0",
"less": "^4.2.0",
"mockjs": "^1.1.0",
"pinia": "^2.1.7",
@ -1024,6 +1025,20 @@
"node": ">=0.4.0"
}
},
"node_modules/echarts": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.5.0.tgz",
"integrity": "sha512-rNYnNCzqDAPCr4m/fqyUFv7fD9qIsd50S6GDFgO1DxZhncCsNsG7IfUlAlvZe5oSEQxtsjnHiUuppzccry93Xw==",
"dependencies": {
"tslib": "2.3.0",
"zrender": "5.5.0"
}
},
"node_modules/echarts/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"node_modules/ee-first": {
"version": "1.1.1",
"license": "MIT"
@ -2058,6 +2073,19 @@
"version": "3.1.1",
"dev": true,
"license": "ISC"
},
"node_modules/zrender": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.5.0.tgz",
"integrity": "sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==",
"dependencies": {
"tslib": "2.3.0"
}
},
"node_modules/zrender/node_modules/tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
}
}
}

View File

@ -11,6 +11,9 @@
"dependencies": {
"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",
"mockjs": "^1.1.0",
"pinia": "^2.1.7",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

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

@ -1,8 +1,17 @@
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 APILoansAdd(data) {
return request.post('/post-sdy-loan-add', data)
}

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

@ -31,6 +31,9 @@
<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-submenu>
<t-submenu value="3" title="应收款管理">
<template #icon>
@ -42,6 +45,12 @@
<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-submenu>
<t-submenu value="4" title="学生管理">
<template #icon>

View File

@ -174,6 +174,7 @@
<t-input
v-model="dialogData.billserial"
placeholder="请输入票据编号"
maxlength="10"
></t-input>
</t-form-item>
<t-form-item

View File

@ -206,6 +206,13 @@ const columns = ref([
align: "center",
width: "100",
},
{
colKey: "breakInfo",
title: "报损原因",
ellipsis: true,
align: "center",
width: "100",
},
{
colKey: "status",
title: "操作",
@ -337,12 +344,13 @@ const FORM_RULES = {
const breakSub = async ({ validateResult, firstError }) => {
if (validateResult === true) {
dialogData.value = {
...rowItem.row.value,
...rowItem.value.row,
breakStatus: Number(dialogData.value.Status),
};
await destroyList.auditDestroyList(dialogData.value);
getNewTable();
MessagePlugin.success("提交成功");
visiblePost.value = false;
MessagePlugin.success("提交成功");
} else {
console.log("Validate Errors: ", firstError, validateResult);
}

View File

@ -75,6 +75,9 @@
class="table"
:max-height="550"
>
<template #stockNum="{ row }">
{{ `${row.stockNum}` }}
</template>
<template #billType="{ row }">
<div v-for="item in billType" :key="item">
<span v-if="row.billType === item.value">{{ item.label }}</span>
@ -134,6 +137,7 @@
<t-input
v-model="dialogData.billserial"
placeholder="请输入票据编号"
maxlength="10"
></t-input>
</t-form-item>
<t-form-item
@ -167,17 +171,6 @@
placeholder="请输入入库数量"
></t-input>
</t-form-item>
<t-form-item
label="入库单位"
name="unit"
:span="10"
style="margin-bottom: 0.5rem"
>
<t-input
v-model="dialogData.unit"
placeholder="请输入入库单位"
></t-input>
</t-form-item>
<t-form-item
label="入库时间"
name="stockDate"
@ -260,12 +253,6 @@ const columns = ref([
align: "center",
width: "100",
},
{
colKey: "unit",
title: "单位(如:本、张)",
align: "center",
width: "100",
},
{
colKey: "stockDate",
title: "入库日期",

View File

@ -0,0 +1,259 @@
<template>
<div class="back-color" style="overflow-y: hidden">
<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"
>
<div style="margin-left: 1rem">
<t-form-item label="部门:" name="branch">
<t-input v-model="scarchData.branch"></t-input>
</t-form-item>
</div>
<t-form-item style="margin-right: 1rem">
<t-button theme="primary" type="submit">查询</t-button>
<t-button theme="primary" type="reset">重置</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" @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"
>
<template #quitneckNum="{ row }">
{{ `${row.quitneckNum}` }}
</template>
</t-base-table>
</t-content>
</t-layout>
</div>
</template>
<script setup>
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">
.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,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,40 @@
<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(["Jan", "Feb", "Mar", "Apr", "May", "Jun"]);
const legendList = ref(["series1", "series2"]);
const seriesData = ref([
{
name: "series1",
data: [10, 20, 15, 20, 25, 30],
type: "line",
}, //
{
name: "series2",
data: [15, 22, 18, 28, 25, 32],
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>

View File

@ -1,7 +1,41 @@
<template>
<div></div>
<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></script>
<script setup>
import homeHeader from "./components/homeHeader.vue";
import homeCenter from "./components/homeCenter.vue";
import homeFooter from "./components/homeFooter.vue";
</script>
<style lang="scss" scoped></style>
<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>

View File

@ -14,6 +14,9 @@
<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>
@ -170,6 +173,7 @@ const editableCellState = cellParams => {
return row.status !== 2
}
const tableRef = ref()
//
const columns = computed(() => [
{
title: '学生姓名',
@ -289,12 +293,22 @@ const columns = computed(() => [
},
{
title: '操作',
colKey: 'operation'
width: 300,
colKey: 'operation',
align: 'center'
}
])
//
const handleEdit = row => {
router.push({
path: 'bill-bill',
path: '/bill-bill',
query: row
})
}
//
const waivarForm = row => {
router.push({
path: '/waivar-form',
query: row
})
}

View File

@ -0,0 +1,7 @@
<template>
<div>1</div>
</template>
<script setup></script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,402 @@
<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">
<t-button type="submit" class="button" style="margin-left: -0.5rem"
>搜索</t-button
>
<t-button type="reset" style="margin-left: 1.5rem">重置</t-button>
</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="-"
resizable
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
} 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,
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 = () => {
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
}
//
const onReset = () => {
LoansList()
}
//
const onSubmit = async () => {}
//
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

@ -5,6 +5,7 @@ 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";
const financeBillManage = [
{
@ -61,6 +62,14 @@ const financeBillManage = [
title: "票据核销",
},
},
{
path: "DetailReport",
name: "detailReport",
component: DetailReportURL,
meta: {
title: "报表明细",
},
},
],
},
];

View File

@ -25,6 +25,24 @@ const ReceivablesManagement = [
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: "收费日报", },
}
],
},

View File

@ -8,15 +8,32 @@ export const useDestroy = defineStore("destroyList", {
},
actions: {
async getDestroyList() {
this.destroyList = JSON.parse(
localStorage.getItem("breakageList")
).destroyList;
console.log(this.destroyList);
const storedData = localStorage.getItem("breakageList");
if (storedData) {
const parsedData = JSON.parse(storedData);
this.destroyList = parsedData.destroyList;
}
return this.destroyList;
},
auditDestroyList(item) {
console.log(item);
// let arr = thisz
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) => {
console.log(i.id, item.id);
if (i.id === item.id) {
console.log(item.breakStatus);
return { ...i, breakStatus: item.breakStatus }; // 返回更新后的对象
}
return i; // 保持其他项不变
});
console.log(parsedData.breakageList);
localStorage.setItem("breakageList", JSON.stringify(parsedData));
this.destroyList = parsedData.destroyList; // 更新store中的destroyList状态
}
},
},
persist: true,

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 };