Files
jurong_circle_program_black…/src/views/sun_template.vue
2025-10-13 17:28:26 +08:00

526 lines
14 KiB
Vue

<template>
<div class="page-container">
<el-card class="page-header">
<h2>项目管理</h2>
<p>管理项目的信息</p>
</el-card>
<!-- 统计卡片 -->
<el-card class="stats-card">
<el-row :gutter="24" class="stats-row">
<el-col :span="8">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">{{ stats.totalTransfers }}</div>
<div class="stat-label">总转账数</div>
</div>
<el-icon class="stat-icon">
<Money/>
</el-icon>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">{{ stats.confirmedTransfers }}</div>
<div class="stat-label">已确认</div>
</div>
<el-icon class="stat-icon">
<Check/>
</el-icon>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="stat-card">
<div class="stat-content">
<div class="stat-number">¥{{ stats.totalAmount }}</div>
<div class="stat-label">总欠额</div>
</div>
<el-icon class="stat-icon">
<Wallet/>
</el-icon>
</el-card>
</el-col>
</el-row>
</el-card>
<!-- 筛选和操作 -->
<el-card class="filter-card">
<el-row :gutter="20">
<!-- <el-col :span="4">-->
<!-- <el-select v-model="queryParams.status" placeholder="选择状态" clearable>-->
<!-- <el-option label="全部" value=""/>-->
<!-- <el-option label="待确认" value="pending"/>-->
<!-- <el-option label="已确认" value="confirmed"/>-->
<!-- <el-option label="已拒绝" value="rejected"/>-->
<!-- <el-option label="已取消" value="cancelled"/>-->
<!-- </el-select>-->
<!-- </el-col>-->
<el-col :span="4">
<el-input v-model="queryParams.keyword" placeholder="搜索项目名称、项目公司或地址" clearable/>
</el-col>
<!-- <el-col :span="4">-->
<!-- <el-date-picker-->
<!-- v-model="dateRange"-->
<!-- type="daterange"-->
<!-- range-separator="至"-->
<!-- start-placeholder="开始日期"-->
<!-- end-placeholder="结束日期"-->
<!-- format="YYYY-MM-DD"-->
<!-- value-format="YYYY-MM-DD"-->
<!-- />-->
<!-- </el-col>-->
<el-row style="margin-left: 50px;" :gutter="10">
<el-col :span="12">
<el-button type="primary" @click="getList">搜索</el-button>
</el-col>
<el-col :span="12">
<el-button @click="resetFilters">重置</el-button>
</el-col>
</el-row>
</el-row>
</el-card>
<!-- 数据列表 -->
<el-card class="table-card">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate"
>修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="single"
@click="handleDelete"
>删除
</el-button>
</el-col>
</el-row>
<el-table
:data="dataList"
v-loading="loading"
@selection-change="handleSelectionChange"
stripe
style="width: 100%"
>
<el-table-column type="selection" width="55" align="center"/>
<!-- <el-table-column prop="id" label="ID"/>-->
<el-table-column prop="name" label="项目名称"/>
<el-table-column prop="company" label="项目公司"/>
<el-table-column label="项目负责人">
<template #default="scope">
<el-tag>{{ scope.row.user.username }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="address" label="项目地址"/>
<el-table-column prop="paymentMethod" label="结算方式"/>
<el-table-column prop="startDate" label="开始时间"/>
<el-table-column prop="endDate" label="结束时间"/>
<el-table-column prop="createDate" label="创建时间"/>
<el-table-column prop="introduction" label="项目描述"/>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="300">
<template #default="scope">
<!-- <el-button link type="primary" icon="Document" @click="handleDetail(scope.row)">详情</el-button>-->
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
v-model:current-page="pagination.page"
v-model:page-size="pagination.size"
:page-sizes="[10,50,100]"
:total="pagination.total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="getList"
@current-change="getList"
/>
</div>
</el-card>
<!-- 表单 -->
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="项目名称" prop="name">
<el-input v-model="form.name" placeholder="请输入项目名称"/>
</el-form-item>
<el-form-item label="公司名称" prop="company">
<el-input v-model="form.company" placeholder="请输入公司名称"/>
</el-form-item>
<el-form-item label="项目地点" prop="address">
<el-input v-model="form.address" placeholder="请输入项目地点"/>
</el-form-item>
<el-form-item label="结算方式" prop="paymentMethod">
<el-input v-model="form.paymentMethod" placeholder="请输入结算方式"/>
</el-form-item>
<el-form-item label="项目时间" prop="dataRange">
<el-date-picker
v-model="form.dataRange"
type="daterange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</el-form-item>
<!-- <el-form-item label="开始时间" prop="startDate">-->
<!-- <el-input v-model="form.startDate" placeholder="请选择开始时间"/>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="结束时间" prop="endDate">-->
<!-- <el-input v-model="form.endDate" placeholder="请选择结束时间"/>-->
<!-- </el-form-item>-->
<el-form-item label="项目描述" prop="introduction">
<el-input v-model="form.introduction" placeholder="请输入项目简介"/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import {getCurrentInstance, reactive, ref, toRefs} from "vue";
import {Check, Money, Wallet} from "@element-plus/icons-vue";
import {ElMessage, ElMessageBox} from "element-plus";
import {programAPI} from "@/api/program";
import {useUserStore} from "@/stores/user";
const {proxy} = getCurrentInstance();
const userStore = useUserStore()
// 统计
const stats = ref({
totalTransfers: 10,
confirmedTransfers: 10,
totalAmount: 10
})
const dateRange = ref([])
// 列表
const dataList = ref([])
const loading = ref(false)
const single = ref(true);
// 分页
const pagination = ref({
page: 1,
size: 10,
total: 0
});
// 表单
const open = ref(false)
const title = ref("");
const data = reactive({
form: {},
queryParams: {
page: 1,
size: 10,
name: undefined,
status: undefined,
keyword: undefined
},
rules: {
name: [{required: true, message: "项目名称不能为空", trigger: "blur"}],
company: [{required: true, message: "公司不能为空", trigger: "blur"}],
address: [{required: true, message: "地址不能为空", trigger: "blur"}],
introduction: [{required: true, message: "简介不能为空", trigger: "blur"}],
paymentMethod: [{required: true, message: "结算方式不能为空", trigger: "blur"}],
dataRange: [{required: true, message: "时间不能为空", trigger: "blur"}],
},
});
const {queryParams, form, rules} = toRefs(data);
// TODO
const getStats = () => {
// programAPI.getStats().then(res => {
// stats.value = res.data.data.stats
// })
}
// 加载数据
const getList = async () => {
loading.value = true;
// api请求
queryParams.value.page = pagination.value.page;
queryParams.value.size = pagination.value.size;
programAPI.list(queryParams.value).then(res => {
// console.log(res)
dataList.value = res.data.data.list
pagination.value.total = res.data.data.total
loading.value = false;
})
}
// 重置
const resetFilters = () => {
queryParams.value = {
page: 1,
keyword: undefined
}
dateRange.value = []
getList()
}
const handleSelectionChange = (selection) => {
single.value = selection.length != 1;
}
const handleAdd = () => {
title.value = "新增项目"
open.value = true;
form.value = {}
}
const handleUpdate = (row) => {
programAPI.getOne(row.id).then(res => {
form.value = res.data.data
form.value.dataRange = [form.value.startDate, form.value.endDate]
title.value = "修改项目"
open.value = true;
})
}
const handleDelete = (row) => {
ElMessageBox.confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
programAPI.delete(row.id).then(res => {
ElMessage.success('删除成功')
getList()
})
}).catch(() => {
ElMessage.info('已取消删除')
})
}
// 查看详情
const handleDetail = (row) => {
ElMessage.info('查看详情')
}
const submitForm = () => {
proxy.$refs["formRef"].validate(valid => {
if (valid) {
form.value.linkmanId = userStore.user.id
form.value.startDate = form.value.dataRange[0]
form.value.endDate = form.value.dataRange[1]
if (form.value.id != undefined) {
delete form.value.user;
delete form.value.dataRange;
programAPI.update(form.value).then(res => {
ElMessage.success('修改成功')
open.value = false
getList()
})
} else {
programAPI.add(form.value).then(res => {
ElMessage.success('添加成功')
open.value = false
getList()
})
}
}
})
}
const cancel = () => {
open.value = false
}
// 获取统计
getStats()
// 获取列表
getList();
</script>
<style scoped lang="scss">
.page-container {
padding: 20px;
}
.page-header {
margin-bottom: 20px;
}
.page-header h2 {
margin: 0 0 8px 0;
color: #303133;
}
.page-header p {
margin: 0;
color: #909399;
}
.stats-card {
margin-bottom: 20px;
}
.stats-row {
margin-bottom: 20px;
}
.stat-card {
position: relative;
overflow: hidden;
}
.stat-content {
padding: 20px;
}
.stat-number {
font-size: 28px;
font-weight: bold;
color: #409eff;
margin-bottom: 8px;
}
.stat-label {
color: #909399;
font-size: 14px;
}
.stat-icon {
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
font-size: 40px;
color: #e4e7ed;
}
.stat-card.overdue {
border-left: 4px solid #e6a23c;
}
.stat-card.overdue .stat-icon {
color: #e6a23c;
}
.stat-card.overdue .stat-number {
color: #e6a23c;
}
.filter-card {
margin-bottom: 20px;
}
.table-card {
margin-bottom: 20px;
}
.amount {
font-weight: bold;
color: #67c23a;
}
.amount-red {
font-weight: bold;
color: #ff4949;
}
.pagination-container {
margin-top: 20px;
text-align: right;
}
.proof-container {
text-align: center;
}
.proof-image {
width: 60%;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.proof-section {
margin-top: 20px;
}
.proof-section h4 {
margin-bottom: 10px;
color: #303133;
}
.detail-container {
display: grid;
place-items: center;
}
.detail-buttom {
color: #409eff;
cursor: pointer;
font-size: 10px;
}
.detail-buttom:hover {
text-decoration: underline;
}
.avatar {
width: 100px;
height: 100px;
display: block;
object-fit: cover;
}
.pay-detail-text {
white-space: pre-line;
word-break: break-word;
padding: 10px;
background-color: #f5f7fa;
border-radius: 4px;
border-left: 3px solid #409eff;
font-size: large;
}
.user-balance-info {
margin-top: 5px;
padding: 5px 10px;
background-color: #f5f7fa;
border-radius: 4px;
border-left: 3px solid #409eff;
}
.real-name {
font-size: 12px;
color: #909399;
margin-top: 2px;
}
</style>