Browse Source

修改 bug

master
王泽彦 7 months ago
parent
commit
ec84d19ec4
  1. 23
      admin/src/app/views/contract/contract.vue
  2. 5
      niucloud/app/api/controller/apiController/Contract.php
  3. 2
      niucloud/app/api/route/route.php
  4. 131
      niucloud/app/service/api/apiService/ContractSignFormService.php
  5. 4
      niucloud/app/service/core/sys/CoreFieldMappingService.php
  6. 7
      uniapp/api/apiRoute.js
  7. 225
      uniapp/pages-student/contracts/sign.vue

23
admin/src/app/views/contract/contract.vue

@ -126,11 +126,6 @@
<option value="">请选择合同类型</option>
<option value="内部">内部合同</option>
<option value="外部">外部合同</option>
<option value="员工">员工合同</option>
<option value="学员">学员合同</option>
<option value="会员">会员合同</option>
<option value="培训">培训合同</option>
<option value="服务">服务合同</option>
</select>
</div>
<div class="form-item">
@ -294,29 +289,31 @@
<option v-if="config.table_name === 'school_student'" value="birthday">生日</option>
<option v-if="config.table_name === 'school_student'" value="emergency_contact">紧急联系人</option>
<option v-if="config.table_name === 'school_student'" value="contact_phone">联系电话</option>
<option v-if="config.table_name === 'school_student'" value="member_label">会员标签</option>
<option v-if="config.table_name === 'school_student'" value="user_id">关联用户ID</option>
<option v-if="config.table_name === 'school_student'" value="campus_id">校区ID</option>
<!-- <option v-if="config.table_name === 'school_student'" value="member_label">会员标签</option>-->
<!-- <option v-if="config.table_name === 'school_student'" value="user_id">关联用户ID</option>-->
<option v-if="config.table_name === 'school_student'" value="campus_id">所属校区</option>
<!-- 用户表字段 (school_customer_resources) -->
<option v-if="config.table_name === 'school_customer_resources'" value="id">用户ID</option>
<option v-if="config.table_name === 'school_customer_resources'" value="name">姓名</option>
<!-- <option v-if="config.table_name === 'school_customer_resources'" value="id">用户ID</option>-->
<option v-if="config.table_name === 'school_customer_resources'" value="name">家长姓名</option>
<option v-if="config.table_name === 'school_customer_resources'" value="phone_number">手机号</option>
<option v-if="config.table_name === 'school_customer_resources'" value="campus">所属校区</option>
<option v-if="config.table_name === 'school_customer_resources'" value="member_id">会员ID</option>
<!-- <option v-if="config.table_name === 'school_customer_resources'" value="member_id">会员ID</option>-->
<!-- 订单表字段 (school_order_table) -->
<option v-if="config.table_name === 'school_order_table'" value="id">订单ID</option>
<option v-if="config.table_name === 'school_order_table'" value="payment_id">支付编号</option>
<option v-if="config.table_name === 'school_order_table'" value="order_amount">订单金额</option>
<option v-if="config.table_name === 'school_order_table'" value="course_id">课程</option>
<option v-if="config.table_name === 'school_order_table'" value="class_id">班级</option>
<option v-if="config.table_name === 'school_order_table'" value="staff_id">销售人员</option>
<option v-if="config.table_name === 'school_order_table'" value="campus_id">校区</option>
<option v-if="config.table_name === 'school_order_table'" value="course_plan_id">课程计划</option>
<option v-if="config.table_name === 'school_order_table'" value="student_id">学员ID</option>
<option v-if="config.table_name === 'school_order_table'" value="discount_amount">优惠金额</option>
<!-- <option v-if="config.table_name === 'school_order_table'" value="student_id">学员ID</option>-->
<!-- 员工表字段 (school_personnel) -->
<option v-if="config.table_name === 'school_personnel'" value="id">员工ID</option>
<!-- <option v-if="config.table_name === 'school_personnel'" value="id">员工ID</option>-->
<option v-if="config.table_name === 'school_personnel'" value="name">姓名</option>
<option v-if="config.table_name === 'school_personnel'" value="phone">电话</option>
<option v-if="config.table_name === 'school_personnel'" value="email">邮箱</option>

5
niucloud/app/api/controller/apiController/Contract.php

@ -425,4 +425,9 @@ class Contract extends BaseApiService
return fail('合同签署失败:' . $e->getMessage());
}
}
public function confirmGenerateContract(Request $request)
{
$contract_sign_id = $request->param('contract_sign_id', 0);
}
}

2
niucloud/app/api/route/route.php

@ -613,6 +613,8 @@ Route::group(function () {
Route::post('student/attendance/leave', 'student.AttendanceController/leave');
// 学员取消
Route::post('student/attendance/cancel', 'student.AttendanceController/cancel');
// 员工端生成合同
Route::post('contract/confirmGenerateContract', 'apiController.Contract/confirmGenerateContract');
})->middleware(ApiChannel::class)
->middleware(ApiPersonnelCheckToken::class, true)

131
niucloud/app/service/api/apiService/ContractSignFormService.php

@ -90,6 +90,8 @@ class ContractSignFormService extends BaseApiService
'contract_name' => $contract['contract_name'],
'contract_type' => $contract['contract_type'],
'contract_content' => $contract['contract_content'] ?? '',
'status' => $sign_record['status'],
'sign_file' => $sign_record['sign_file'],
'form_fields' => $form_fields,
'student_info' => [
'id' => $student['id'],
@ -734,27 +736,140 @@ class ContractSignFormService extends BaseApiService
switch ($table_name) {
case 'school_student':
// 学员表:直接从学员信息获取
// 学员表:使用CoreFieldMappingService进行字段映射和转义
$service = new CoreFieldMappingService($config['table_name'], ['id' => $student['id']]);
// 配置枚举映射
$service->setFieldEnums([
'gender' => [0 => '未知', 1 => '男', 2 => '女'],
'status' => [0 => '无效', 1 => '有效', 2 => '过期', 3 => '结业']
]);
// 配置关联字段映射
$service->setFieldRelations([
'user_id' => [
'table' => 'school_customer_resources',
'display_field' => 'name',
'key_field' => 'id'
],
'campus_id' => [
'table' => 'school_campus',
'display_field' => 'campus_name',
'key_field' => 'id'
],
'class_id' => [
'table' => 'school_class',
'display_field' => 'class_name',
'key_field' => 'id'
],
'consultant_id' => [
'table' => 'school_personnel',
'display_field' => 'name',
'key_field' => 'id'
],
'coach_id' => [
'table' => 'school_personnel',
'display_field' => 'name',
'key_field' => 'id'
]
]);
// 检查是否为关联字段,使用链式调用获取关联值
if (in_array($field_name, ['user_id', 'campus_id', 'class_id', 'consultant_id', 'coach_id'])) {
$relation_config = $service->getRelationMapping()[$field_name];
$value = $service->getValueWithChain($field_name)
->withRelation(
$relation_config['table'],
$relation_config['display_field'],
$relation_config['key_field']
);
} else {
// 普通字段或枚举字段,自动转义枚举值
$value = $service->getValue($field_name);
}
break;
case 'school_customer_resources':
// 用户表:通过学员的user_id关联查询
// 客户资源表:通过学员的user_id关联查询
if (!empty($student['user_id'])) {
$service = new CoreFieldMappingService($config['table_name'], ['id' => $student['user_id']]);
// 配置枚举映射
$service->setFieldEnums([
'gender' => ['male' => '男性', 'female' => '女性', 'other' => '其他'],
'initial_intent' => ['high' => '高', 'medium' => '中', 'low' => '低'],
'rf_type' => ['market' => '市场人员新增', 'sale' => '销售人员新增', 'teacher' => '教练新增'],
'blacklist' => [1 => '可追单', 0 => '黑名单']
]);
$value = $service->getValue($field_name);
}
break;
case 'school_order_table':
// 订单表:查询该学员最新的订单信息
$order = OrderTable::where('contract_sign_id',$config['contract_sign_id'])->find();
// 订单表:使用CoreFieldMappingService进行字段映射和转义
$service = new CoreFieldMappingService($config['table_name'], ['contract_sign_id' => $config['contract_sign_id']]);
// 配置枚举映射
$service->setFieldEnums([
'order_type' => [1 => '新订单', 2 => '续费订单', 3 => '内部员工订单', 4 => '转校', 5 => '客户内转课订单'],
'order_status' => ['pending' => '待支付', 'paid' => '已支付', 'signed' => '待签约', 'completed' => '已完成', 'transfer' => '转学'],
'payment_type' => ['cash' => '现金支付', 'scan_code' => '扫码支付', 'subscription' => '订阅支付', 'wxpay_online' => '微信在线代付'],
'gift_type' => [1 => '减现', 2 => '赠课']
]);
$value = Db::table('school_order_table')
->where('student_id', $student['id'])
->order('created_at', 'desc')
->value($field_name) ?? '';
// 配置关联字段映射
$service->setFieldRelations([
'course_id' => [
'table' => 'school_course',
'display_field' => 'course_name',
'key_field' => 'id'
],
'class_id' => [
'table' => 'school_class',
'display_field' => 'class_name',
'key_field' => 'id'
],
'staff_id' => [
'table' => 'school_personnel',
'display_field' => 'name',
'key_field' => 'id'
],
'resource_id' => [
'table' => 'school_customer_resources',
'display_field' => 'name',
'key_field' => 'id'
],
'campus_id' => [
'table' => 'school_campus',
'display_field' => 'CONCAT(campus_name, campus_address)',
'key_field' => 'id'
],
'gift_id' => [
'table' => 'shcool_resources_gift',
'display_field' => 'gift_name',
'key_field' => 'id'
],
'course_plan_id' => [
'table' => 'school_student_courses',
'display_field' => 'CONCAT("正式课时数量:", total_hours, ",赠送课时", gift_hours, ",课程有效期为", start_date, "至", end_date)',
'key_field' => 'id'
]
]);
// 检查是否为关联字段,使用链式调用获取关联值
if (in_array($field_name, ['course_id', 'class_id', 'staff_id', 'resource_id', 'campus_id', 'gift_id', 'course_plan_id'])) {
$relation_config = $service->getRelationMapping()[$field_name];
$value = $service->getValueWithChain($field_name)
->withRelation(
$relation_config['table'],
$relation_config['display_field'],
$relation_config['key_field']
);
} else {
// 普通字段或枚举字段,自动转义枚举值
$value = $service->getValue($field_name);
}
break;
case 'school_personnel':

4
niucloud/app/service/core/sys/CoreFieldMappingService.php

@ -299,6 +299,10 @@ class CoreFieldMappingService extends BaseCoreService
// 尝试从缓存获取
$cached_value = Cache::get($cache_key);
if ($cached_value !== false && $cached_value !== null) {
// 如果需要返回包装对象,将缓存值包装成FieldValue对象
if ($return_wrapper) {
return new FieldValue($cached_value, $this, $field_name);
}
return $cached_value;
}
}

7
uniapp/api/apiRoute.js

@ -1755,6 +1755,13 @@ export default {
})
},
// 确认生成合同
async confirmGenerateContract(data = {}) {
return await http.post('/contract/confirmGenerateContract', {
contract_sign_id: data.contract_sign_id,
})
},
// 下载合同文件
async downloadStudentContract(data = {}) {
const params = {

225
uniapp/pages-student/contracts/sign.vue

@ -149,15 +149,41 @@
<!-- 提交按钮 -->
<view class="submit_section" v-if="!loading">
<fui-button
type="warning"
btn-size="medium"
width="100%"
<!-- 当status=2且sign_file为空时显示确认生成合同和修改合同按钮 -->
<view v-if="contractInfo && contractInfo.status == 2 && !contractInfo.sign_file" class="button_group">
<button
class="uni-button generate-btn"
:loading="generating"
@click="confirmGenerateContract"
>
{{ generating ? '生成中...' : '确认生成合同' }}
</button>
<button
class="uni-button modify-btn"
@click="submitContract"
>
修改合同
</button>
</view>
<!-- 当status=2且sign_file有值时显示下载合同按钮 -->
<button
v-else-if="contractInfo && contractInfo.status == 3 && contractInfo.sign_file"
class="uni-button download-btn"
@click="downloadContract"
>
下载合同
</button>
<!-- 其他情况显示原有的提交签署按钮 -->
<button
v-else
class="uni-button submit-btn"
:loading="submitting"
@click="submitContract"
>
{{ submitting ? '提交中...' : '提交签署' }}
</fui-button>
</button>
</view>
</view>
</template>
@ -180,6 +206,7 @@
formData: {},
loading: true,
submitting: false,
generating: false, //
//
userInfo: null,
userRole: 'student', //
@ -441,8 +468,11 @@
if (response.code === 1) {
const data = response.data
this.contractInfo = {
contract_sign_id: data.contract_sign_id,
contract_name: data.contract_name,
contract_type: data.contract_type
contract_type: data.contract_type,
status: data.status,
sign_file: data.sign_file
}
this.contractContent = data.contract_content || ''
this.formFields = data.form_fields || []
@ -694,6 +724,118 @@
} finally {
this.submitting = false
}
},
//
async confirmGenerateContract() {
this.generating = true
try {
console.log('确认生成合同:', {
contractSignId: this.contractSignId
})
const response = await apiRoute.confirmGenerateContract({
contract_sign_id: this.contractSignId
})
if (response.code === 1) {
uni.showToast({
title: '合同生成成功',
icon: 'success',
duration: 2000
})
//
setTimeout(() => {
this.loadSignForm()
}, 2000)
} else {
uni.showToast({
title: response.msg || '合同生成失败',
icon: 'none'
})
}
} catch (error) {
console.error('合同生成失败:', error)
uni.showToast({
title: '合同生成失败',
icon: 'none'
})
} finally {
this.generating = false
}
},
//
downloadContract() {
if (!this.contractInfo || !this.contractInfo.sign_file) {
uni.showToast({
title: '合同文件不存在',
icon: 'none'
})
return
}
//
uni.showLoading({
title: '准备下载...',
mask: true
})
// URL
const fileUrl = this.contractInfo.sign_file.startsWith('http')
? this.contractInfo.sign_file
: Api_url + this.contractInfo.sign_file
//
uni.downloadFile({
url: fileUrl,
success: (res) => {
uni.hideLoading()
if (res.statusCode === 200) {
//
uni.saveFile({
tempFilePath: res.tempFilePath,
success: (saveRes) => {
uni.showToast({
title: '下载成功',
icon: 'success'
})
//
uni.openDocument({
filePath: saveRes.savedFilePath,
success: () => {
console.log('打开文档成功')
},
fail: (err) => {
console.error('打开文档失败:', err)
}
})
},
fail: (err) => {
console.error('保存文件失败:', err)
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
})
} else {
uni.showToast({
title: '下载失败',
icon: 'none'
})
}
},
fail: (err) => {
uni.hideLoading()
console.error('下载失败:', err)
uni.showToast({
title: '下载失败',
icon: 'none'
})
}
})
}
}
}
@ -1079,13 +1221,82 @@
bottom: 0;
left: 0;
right: 0;
background: #fff;
background: rgba(255, 255, 255, 0.98);
backdrop-filter: blur(10rpx);
padding: 20rpx 32rpx 40rpx;
border-top: 1rpx solid #f0f0f0;
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
z-index: 999;
//
// #ifdef MP-WEIXIN
padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
// #endif
//
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #fff;
z-index: -1;
}
//
.button_group {
display: flex;
justify-content: space-between;
align-items: center;
gap: 20rpx;
}
// UniApp
.uni-button {
height: 88rpx;
line-height: 88rpx;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 500;
border: none;
outline: none;
&.generate-btn {
flex: 1;
background: linear-gradient(135deg, #FF6B35 0%, #F7931E 100%);
color: #fff;
}
&.modify-btn {
flex: 1;
background: linear-gradient(135deg, #29D3B4 0%, #1BA89A 100%);
color: #fff;
}
&.download-btn {
width: 100%;
background: linear-gradient(135deg, #52C41A 0%, #389E0D 100%);
color: #fff;
}
&.submit-btn {
width: 100%;
background: linear-gradient(135deg, #FF6B35 0%, #F7931E 100%);
color: #fff;
}
//
&:active {
opacity: 0.8;
transform: scale(0.98);
}
//
&[loading] {
opacity: 0.7;
}
}
}
</style>
Loading…
Cancel
Save