This commit is contained in:
Lx 2025-06-06 17:33:22 +08:00
parent 14d7ac0ef9
commit 9bad0f6202
12 changed files with 391 additions and 251 deletions

View File

@ -138,6 +138,19 @@
<!--地址<el-input type="text" v-model="detailedAddress" style="width: 250px;" />-->
</el-form-item>
<el-form-item label="app_id" prop="appId">
<el-input v-model="formData.appId" placeholder="请输入appId" maxlength="255"/>
</el-form-item>
<el-form-item label="mch_id" prop="mchId">
<el-input v-model="formData.mchId" placeholder="请输入mchId" maxlength="255"/>
</el-form-item>
<el-form-item label="回调地址" prop="notifyUrl">
<el-input v-model="formData.notifyUrl" placeholder="请输入微信支付回调地址" maxlength="255"/>
</el-form-item>
<el-form-item label="私钥" prop="privateKeyStr">
<el-input type="textarea" v-model="formData.privateKeyStr" maxlength="900" placeholder="请输入私钥"/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
@ -204,7 +217,11 @@ export default {
businessStartTime: null,
businessEndTime: null,
lat: null,
lgt: null
lgt: null,
appId: null,
mchId: null,
notifyUrl: null,
privateKeyStr: null,
},
//
formRules: {
@ -355,7 +372,11 @@ export default {
businessStartTime: null,
businessEndTime: null,
lat: null,
lgt: null
lgt: null,
appId: null,
mchId: null,
notifyUrl: null,
privateKeyStr: null,
}
//
this.lng = "";

View File

@ -11,6 +11,36 @@
<el-form-item label="业务经理" prop="businessName">
<el-input v-model="queryParams.businessName" placeholder="请输入业务经理姓名" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="订单状态" prop="paymentStatus">
<el-select
v-model="queryParams.paymentStatus"
placeholder="请选择订单状态"
clearable
@keyup.enter.native="handleQuery"
>
<el-option label="待支付" value="0" />
<el-option label="已取消" value="1" />
<el-option label="已支付(已报名)" value="2" />
<el-option label="待面签" value="3" />
<el-option label="已面签" value="4" />
<el-option label="已完成" value="5" />
<el-option label="申请退款" value="6" />
<el-option label="退款中" value="7" />
<el-option label="退款成功" value="8" />
</el-select>
</el-form-item>
<el-form-item label="是否面签" prop="isSign">
<el-select
v-model="queryParams.isSign"
placeholder="请选择面签状态"
clearable
@keyup.enter.native="handleQuery"
>
<el-option label="否" value="0" />
<el-option label="是" value="1" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
@ -92,7 +122,11 @@ export default {
pageSize: 10,
name: null,
phone: null,
type: null
type: null,
paymentStatus: null,
isSign: null,
businessName: null,
businessPhone: null,
},
};
},

View File

@ -53,11 +53,13 @@
<!-- <span>{{ parseTime(scope.row.endTime) }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="订单状态" align="center" prop="paymentStatus">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.DRIVE_SCHOOL_ORDER_STATUS" :value="scope.row.paymentStatus"/>
</template>
</el-table-column>
<el-table-column label="支付渠道" align="center" prop="payChannel" :formatter="formatPayChannel"/>
<el-table-column label="是否已面签" align="center" prop="isSign">
<template slot-scope="scope">
<el-tag v-if="scope.row.isSign == 1" type="success"></el-tag>
@ -70,7 +72,9 @@
<dict-tag :type="DICT_TYPE.DRIVE_SCHOOL_PAY_TYPE" :value="scope.row.payType"/>
</template>
</el-table-column>
<el-table-column label="报名时间" align="center" prop="createTime" :formatter="formatDate"/>
<el-table-column label="报名方式" align="center" prop="signType" :formatter="formatSignType"/>
<!-- <el-table-column label="学费到账审核" align="center" prop="receiptReview" :formatter="formatReceiptReview"/>-->
<el-table-column label="信息" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
@ -525,6 +529,20 @@ export default {
return `${year}-${month}-${day}`;
},
formatPayChannel(row, column, value) {
const map = {
'1': '微信支付',
'2': '线下支付'
};
return map[value] ?? '-';
},
formatSignType(row, column, value) {
const map = {
'1': '代报名'
};
return map[value] ?? '-';
},
}
};

View File

@ -35,7 +35,7 @@ export function getProcessAndBatch(id) {
}
// 获得驾校-学员课程进度分页
export function getprocessPage(params) {
export function getProcessPage(params) {
return request({
url: '/process/page',
method: 'get',

View File

@ -129,7 +129,7 @@ export default {
async getList() {
try {
this.loading = true;
const res = await processApi.getprocessPage(this.queryParams);
const res = await processApi.getProcessPage(this.queryParams);
this.list = res.data.records;
this.total = res.data.total;
} finally {

View File

@ -45,6 +45,8 @@
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="教练姓名" align="center" prop="coachName" />
<el-table-column label="学生姓名" align="center" prop="studentName" />
<el-table-column label="课程名称" align="center" prop="courseName" />
<el-table-column label="课程类型" align="center" prop="courseType" />
<el-table-column label="提成金额" align="center" prop="commissionAmount" />
<el-table-column label="科目" align="center" prop="subject" />
<el-table-column label="审核人姓名" align="center" prop="checkName" />

View File

@ -27,9 +27,9 @@ export function getprocess(id) {
}
// 获得驾校-学员课程进度分页
export function getprocessPage(params) {
export function getProcessPage(params) {
return request({
url: '/process/page',
url: '/process/newPage',
method: 'get',
params
})

View File

@ -272,6 +272,22 @@ export default {
async submitForm() {
//
await this.$refs["formRef"].validate();
if (this.formData.examStatus !== '1') {
try {
//
await this.$confirm('当前学员考试状态不是已通过状态,是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
});
// ""
} catch (error) {
// ""
return;
}
}
this.formLoading = true;
try {
const data = this.formData;

View File

@ -1,5 +1,32 @@
<template>
<div class="app-container">
<el-tabs v-model="activeTab" @tab-click="handleTabChange">
<!-- <el-tab-pane label="全部" name="all"></el-tab-pane>-->
<el-tab-pane label="待审核" name="null"></el-tab-pane>
<el-tab-pane label="已通过审核" name="1"></el-tab-pane>
<el-tab-pane label="未通过审核" name="0"></el-tab-pane>
</el-tabs>
<!-- <el-tabs v-model="activeTab" @tab-click="handleTabChange">
<el-tab-pane label="全部" name="all"></el-tab-pane>
<el-tab-pane label="待审核" name="null"></el-tab-pane>
<el-tab-pane label="已审核">
<template #label>
<el-dropdown @command="handleAuditedTabChange" trigger="click">
<span class="el-dropdown-link">
已审核<el-icon class="el-icon&#45;&#45;right"><arrow-down /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="1">已通过</el-dropdown-item>
<el-dropdown-item command="0">未通过</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
</el-tab-pane>
</el-tabs>-->
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="课程名称" prop="courseName">
@ -25,6 +52,15 @@
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="openForm(undefined)">新增</el-button>
</el-col>
<el-col :span="1.5" style="display: flex; align-items: center;">
<span style="margin-right: 10px; font-size: 14px;">只显示已通过考试学员</span>
<el-switch
v-model="showPassedOnly"
active-color="#13ce66"
inactive-color="#dcdfe6"
@change="togglePassedStudents"
/>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@ -65,6 +101,7 @@
<span v-if="scope.row.financePass == 0">未通过</span>
</template>
</el-table-column>
<el-table-column label="财务审核备注" width="120" align="center" prop="financeRemark"/>
<el-table-column label="操作" width="120" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="openForm(scope.row.id,true)">查看</el-button>
@ -83,13 +120,17 @@
<script>
import * as processApi from '@/views/drivingSchool/process/api';
import processForm from '@/views/drivingSchool/process/form/processForm.vue';
// import { ArrowDown } from '@/element-plus/icons-vue';
export default {
name: "process",
components: {
processForm,
// ArrowDown
},
data() {
return {
activeTab: 'all',
showPassedOnly: false,
//
loading: true,
//
@ -114,9 +155,12 @@ export default {
coachName: null,
userName: null,
studentIdCard:null,
financePass: undefined,
examStatus:undefined,
},
};
},
created() {
this.getList();
},
@ -125,13 +169,14 @@ export default {
async getList() {
try {
this.loading = true;
const res = await processApi.getprocessPage(this.queryParams);
const res = await processApi.getProcessPage(this.queryParams);
this.list = res.data.records;
this.total = res.data.total;
} finally {
this.loading = false;
}
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNo = 1;
@ -140,6 +185,8 @@ export default {
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.showPassedOnly = false;
this.queryParams.examStatus = undefined;
this.handleQuery();
},
/** 添加/修改操作 */
@ -168,7 +215,41 @@ export default {
this.exportLoading = false;
}
},
/** Tab切换事件 */
handleTabChange(tab) {
this.queryParams.pageNo = 1;
if (tab.paneName === 'all') {
this.queryParams.financePass = '1';
} else {
this.queryParams.financePass = tab.paneName === 'null' ? null : tab.paneName;
}
this.getList();
},
/** 切换是否只显示已通过考试的学员 */
togglePassedStudents() {
this.queryParams.pageNo = 1;
this.queryParams.examStatus = this.showPassedOnly ? '1' : undefined;
this.getList();
},
/* handleTabChange(tab) {
this.queryParams.pageNo = 1;
if (tab.paneName === 'all') {
this.queryParams.financePass = undefined;
} else {
this.queryParams.financePass = tab.paneName === 'null' ? null : undefined;
}
this.getList();
},
/!** 已审核Tab下的子选项切换事件 *!/
handleAuditedTabChange(command) {
this.activeTab = 'audited'; //
this.queryParams.pageNo = 1;
this.queryParams.financePass = command === '1' ? true : false;
this.getList();
} */
}
};
</script>

View File

@ -27,7 +27,7 @@
<el-input type="textarea" v-model="formData.reportContent" :autosize="{ minRows: 6, maxRows: 10 }"/>
</el-form-item>
<el-form-item label="汇报附件" prop="reportFiles">
<insp-file-upload
<drive-file-upload
:fileSize="30"
:fileType="['doc', 'xls', 'ppt', 'txt', 'pdf','png','jpg','jpeg','gif','docx','xlsx','pptx','wps']"
v-model="formData.filePath"/>

View File

@ -44,6 +44,19 @@
</el-table-column>
<el-table-column label="汇报内容" align="center" prop="reportContent" show-overflow-tooltip/>
<el-table-column label="汇报人" align="center" prop="userName"/>
<el-table-column label="附件" align="center" width="100">
<template v-slot="scope">
<el-button
v-if="scope.row.filePath"
size="mini"
type="text"
@click="handleViewFiles(scope.row.filePath)"
>
查看附件
</el-button>
<span v-else>无附件</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="workReportView(scope.row.id)">打印
@ -56,11 +69,60 @@
</el-table-column>
</el-table>
<el-dialog :visible.sync="showView" width="50%" center>
<div v-html="htmText" id="printMe"></div>
<el-button type="primary" style="margin-left: 90%;margin-top:20px " v-print="'#printMe'" size="small">打印
</el-button>
<el-dialog :title="'文件预览(' + currentFileName + ''" :visible.sync="fileDialogVisible" width="70%" append-to-body>
<div class="preview-container">
<!-- 左侧预览区域 -->
<!-- 音频文件 -->
<audio v-if="isAudioType" class="preview-iframe" controls>
<source :src="currentFileUrl"/>
</audio>
<!-- Office文档/文本/PDF -->
<iframe
v-else-if="!isImageType && currentFileType !== 'txt' && !isAudioType && currentFileType !== 'pdf'"
:src="officePreviewUrl"
frameborder="0"
class="preview-iframe"
></iframe>
<!-- 图片预览 -->
<image-preview
v-else-if="isImageType"
class="preview-iframe"
:src="currentFileUrl"
></image-preview>
<!-- PDF/文本 -->
<iframe
v-else-if="currentFileType === 'txt' || currentFileType === 'pdf'"
:src="currentFileUrl"
frameborder="0"
class="preview-iframe"
></iframe>
<!-- 右侧文件列表 -->
<div class="file-list" v-if="currentFileList.length > 1">
<el-table
:data="currentFileList"
height="100%"
@row-click="handleFileClick"
:row-class-name="getRowClassName">
<el-table-column
prop="fileName"
label="文件列表"
min-width="180">
<template #default="{ row }">
<div class="file-item">
<i :class="getFileIcon(row)"></i>
{{ getFileName(row) }}
</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
</el-dialog>
<!-- 分页组件 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getList"/>
@ -115,8 +177,26 @@ export default {
servicePackageId: "jiaxiao",
dictType:'drive_school_report_role',
},
fileDialogVisible: false,
currentFileList: [],
activeFileTab: 0,
baseUrl: process.env.VUE_APP_BASE_API,
currentFileUrl: '',
currentFileName: '',
currentFileType: '',
officePreviewUrl: '',
};
},
computed: {
isImageType() {
return /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(this.currentFileUrl);
},
isAudioType() {
const audioExtensions = ['mp3', 'wav', 'ogg', 'aac', 'm4a', 'flac'];
return audioExtensions.some(ext => this.currentFileUrl.endsWith(ext));
}
},
created() {
this.getList();
},
@ -175,6 +255,123 @@ export default {
this.exportLoading = false;
}
},
//
handleViewFiles(filePath) {
if (!filePath) {
this.$message.warning('没有附件');
return;
}
//
this.currentFileList = filePath.split(',').filter(item => item.trim());
this.fileDialogVisible = true;
//
if (this.currentFileList.length > 0) {
this.previewFile(this.currentFileList[0]);
}
},
// URLAPI
getFullFileUrl(filePath) {
if (!filePath) return '';
// URLbase64
if (filePath.startsWith('http') || filePath.startsWith('data:')) {
return filePath;
}
// API
const baseUrl = 'http://122.51.230.86:9000/' || '';
return `${baseUrl.replace(/\/$/, '')}/${filePath.replace(/^\//, '')}`;
},
//
getFileName(filePath) {
return filePath.split('/').pop() || '未命名文件';
},
//
isImage(filePath) {
return /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(filePath);
},
//
previewFile(filePath) {
this.currentFileUrl = this.getFullFileUrl(filePath);
this.currentFileName = this.getFileName(filePath);
this.currentFileType = this.getFileExtension(filePath);
// OfficeURL
this.officePreviewUrl = 'https://view.officeapps.live.com/op/view.aspx?src=' +
encodeURIComponent(this.currentFileUrl);
},
//
getFileExtension(filePath) {
return filePath.split('.').pop().toLowerCase();
},
//
getFileIcon(filePath) {
return this.isImage(filePath) ? 'el-icon-picture' : 'el-icon-document';
},
//
handleFileClick(row) {
this.previewFile(row);
},
//
getRowClassName({row}) {
return row === this.currentFileUrl ? 'highlight-row' : '';
},
}
};
</script>
<style scoped>
.image-preview {
display: flex;
justify-content: center;
margin: 20px 0;
}
.image-preview img {
max-height: 500px;
max-width: 100%;
border: 1px solid #eee;
}
.preview-container {
display: flex;
height: 70vh;
}
.preview-iframe {
flex: 1;
width: 100%;
height: 100%;
border: none;
}
.file-list {
flex: 0 0 250px;
border-left: 1px solid #ebeef5;
padding-left: 10px;
margin-left: 10px;
}
.file-item {
cursor: pointer;
padding: 8px;
transition: background 0.3s;
}
.file-item:hover {
background: #f5f7fa;
}
.highlight-row {
background-color: #f0f7ff;
}
</style>

View File

@ -1,257 +1,28 @@
<template>
<div class="container_">
<!-- <div class="top-list">-->
<!-- <div class="list-box" v-for="(item, index) in serviceList" :key="item.id" :span="4">-->
<!-- <div @click="goRoute(item.id)">-->
<!-- <img :src="imgUrl + item.coverImg"-->
<!-- style="width: 300px; height: 300px;">-->
<!-- <div style="font-weight: bold;text-align: center;font-size: 28px">{{ item.name }}</div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<div class="container-box">
<div class="flex-box">
<div style=" font-size: 30px;margin-bottom: 30px">临期提醒</div>
<el-table
:data="warnList"
stripe
style="width: 100%">
<el-table-column
prop="title"
label="标题"
width="180">
</el-table-column>
<el-table-column
prop="content"
label="内容"
width="180">
</el-table-column>
<el-table-column
prop="warnTime"
label="提醒时间">
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="warnTotal > 0" :total="warnTotal" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
@pagination="getWarnList"
/>
</div>
<div class="flex-box">
<div style="font-size: 30px;margin-bottom: 30px">消息通知</div>
<el-table
:data="messageList"
stripe
style="width: 100%">
<el-table-column
prop="templateNickname"
label="发送人"
width="120">
</el-table-column>
<el-table-column label="发送时间" align="center" prop="createTime" width="180">
<template v-slot="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="类型" align="center" prop="templateType" width="80">
<template v-slot="scope">
<dict-tag :type="DICT_TYPE.SYSTEM_NOTIFY_TEMPLATE_TYPE" :value="scope.row.templateType" />
</template>
</el-table-column>
<el-table-column
prop="templateContent"
label="内容">
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination v-show="messageTotal > 0" :total="messageTotal" :page.sync="messageQueryParams.pageNo"
:limit.sync="messageQueryParams.pageSize"
@pagination="getNotifyMessage"
/>
</div>
</div>
<img class="fullscreen-image" src="@/assets/images/homeImg.png" alt="首页图片">
</div>
<!-- <div class="container_">
<div class="fullscreen-image-container">
<img class="fullscreen-image" src="@/assets/images/homeImg.png" alt="Fullscreen Image">
</div>
</div>-->
</template>
<script>
import PanelGroup from './dashboard/PanelGroup'
import LineChart from './dashboard/LineChart'
import RaddarChart from './dashboard/RaddarChart'
import PieChart from './dashboard/PieChart'
import BarChart from './dashboard/BarChart'
import {getServicePackageList} from "@/api/system/servicePackage";
import {warnList,getMyNotifyMessagePage} from "@/api/system/notify/message";
const lineChartData = {
newVisitis: {
expectedData: [100, 120, 161, 134, 105, 160, 165],
actualData: [120, 82, 91, 154, 162, 140, 145]
},
messages: {
expectedData: [200, 192, 120, 144, 160, 130, 140],
actualData: [180, 160, 151, 106, 145, 150, 130]
},
purchases: {
expectedData: [80, 100, 121, 104, 105, 90, 100],
actualData: [120, 90, 100, 138, 142, 130, 130]
},
shoppings: {
expectedData: [130, 140, 141, 142, 145, 150, 160],
actualData: [120, 82, 91, 154, 162, 140, 130]
}
}
export default {
name: 'Index',
components: {
PanelGroup,
LineChart,
RaddarChart,
PieChart,
BarChart
},
data() {
return {
imgUrl:'',
lineChartData: lineChartData.newVisitis,
serviceList: [],
warnList: [],
messageList: [],
queryParams: {
pageNo: 1,
pageSize: 10
},
messageQueryParams: {
pageNo: 1,
pageSize: 10
},
messageTotal: 0,
warnTotal: 0
}
},
created() {
this.getServiceList()
this.getNotifyMessage()
this.getWarnList()
this.imgUrl = process.env.VUE_APP_IMAGE_URL
console.log( this.imgUrl + '1111111' )
},
methods: {
handleSetLineChartData(type) {
this.lineChartData = lineChartData[type]
},
goRoute(code){
console.log(window.location.host,150)
window.open(window.location.origin+"/index?routeCode="+code)
},
getNotifyMessage() {
//
getMyNotifyMessagePage(this.messageQueryParams).then(response => {
this.messageList = response.data.list;
this.messageTotal = response.data.total;
});
},
getWarnList() {
//
warnList(this.queryParams).then(response => {
console.log(response,149)
this.warnList = response.data.records;
this.warnTotal = response.data.total;
});
},
getServiceList() {
getServicePackageList(this.queryParams).then(response => {
this.serviceList = response.data;
});
}
}
name: 'Index'
}
</script>
<style lang="scss" scoped>
.container_{
background-color: rgb(240, 242, 245);
box-sizing: border-box;
padding: 15px;
}
.top-list{
.container_ {
width: 100%;
display: flex;
justify-content: space-between;
margin-bottom: 25px;
flex-wrap: wrap;
}
.list-box{
background: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
border-radius: 4px;
box-sizing: border-box;
padding: 15px;
border-radius: 8px;
}
.container-box{
width: 100%;
display: flex;
justify-content: space-between;
}
.flex-box{
width: 49%;
background: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
border-radius: 4px;
box-sizing: border-box;
padding: 15px;
border-radius: 8px;
}
.dashboard-editor-container {
padding: 32px;
background-color: rgb(240, 242, 245);
position: relative;
.chart-wrapper {
background: #fff;
padding: 16px 16px 0;
margin-bottom: 32px;
}
}
@media (max-width: 1024px) {
.chart-wrapper {
padding: 8px;
}
}
/*.fullscreen-image-container {
//position: fixed;
top: 0;
left: 0;
width: 100%;
height: 50%;
overflow: hidden;
height: calc(100vh - 100px);
margin: 0;
padding: 0;
padding: 5px;
overflow: hidden;
.fullscreen-image {
width: 100%;
height: 100%;
object-fit: cover;
//object-fit: cover;
object-fit: fill;
}
}*/
}
</style>