智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

503 lines
16 KiB

<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\api\apiService;
use app\model\contract\Contract;
use app\model\contract_sign\ContractSign;
use core\base\BaseApiService;
use think\facade\Db;
use PhpOffice\PhpWord\TemplateProcessor;
use app\service\core\contract_sign\ContractSign as ContractSignService;
/**
* 合同服务层
* Class ContractService
* @package app\service\api\apiService
*/
class ContractService extends BaseApiService
{
/**
* 获取我的合同列表
* @param array $where
* @return array
*/
public function getMyContracts(array $where)
{
$res = [
'code' => 0,
'msg' => '获取合同列表失败',
'data' => []
];
try {
$page = $where['page'] ?? 1;
$limit = $where['limit'] ?? 10;
$personnel_id = $where['personnel_id'] ?? 0;
if (empty($personnel_id)) {
$res['msg'] = '员工ID不能为空';
return $res;
}
// 查询合同签订记录,关联合同表
$contractSignModel = new ContractSign();
$list = $contractSignModel->alias('cs')
->join('school_contract c', 'cs.contract_id = c.id')
->where('cs.personnel_id', $personnel_id)
->where('cs.deleted_at', 0)
->where('c.deleted_at', 0)
->field([
'cs.id',
'cs.contract_id',
'cs.personnel_id',
'cs.sign_file',
'cs.status',
'cs.created_at',
'cs.sign_time',
'c.contract_name',
'c.contract_template',
'c.contract_status',
'c.contract_type',
'c.remarks'
])
->order('cs.created_at', 'desc')
->paginate([
'list_rows' => $limit,
'page' => $page
])
->toArray();
$res = [
'code' => 1,
'msg' => '获取成功',
'data' => $list
];
} catch (\Exception $e) {
$res['msg'] = '获取合同列表异常:' . $e->getMessage();
}
return $res;
}
/**
* 获取合同详情
* @param array $where
* @return array
*/
public function getContractDetail(array $where)
{
$res = [
'code' => 0,
'msg' => '获取合同详情失败',
'data' => []
];
try {
$id = $where['id'] ?? 0;
if (empty($id)) {
$res['msg'] = '参数错误';
return $res;
}
// 查询合同签订记录,关联合同表
$contractSign = ContractSign::alias('cs')
->join('school_contract c', 'cs.contract_id = c.id')
->where('cs.id', $id)
->where('cs.deleted_at', 0)
->where('c.deleted_at', 0)
->field([
'cs.id',
'cs.contract_id',
'cs.personnel_id',
'cs.sign_file',
'cs.status',
'cs.created_at',
'cs.sign_time',
'cs.updated_at',
'c.contract_name',
'c.contract_template',
'c.contract_status',
'c.contract_type',
'c.remarks'
])
->find();
if (empty($contractSign)) {
$res['msg'] = '合同不存在或无权限访问';
return $res;
}
$contractData = $contractSign->toArray();
$res = [
'code' => 1,
'msg' => '获取成功',
'data' => $contractData
];
} catch (\Exception $e) {
$res['msg'] = '获取合同详情异常:' . $e->getMessage();
}
return $res;
}
/**
* 签订合同
* @param array $data
* @return array
*/
public function signContract(array $data)
{
$res = [
'code' => 0,
'msg' => '签订合同失败',
'data' => []
];
try {
$contract_id = $data['contract_id'] ?? 0;
$personnel_id = $data['personnel_id'] ?? 0;
$sign_file = $data['sign_file'] ?? '';
if (empty($contract_id) || empty($personnel_id) || empty($sign_file)) {
$res['msg'] = '参数错误';
return $res;
}
// 开启事务
Db::startTrans();
// 查询合同签订记录
$contractSign = ContractSign::where('contract_id', $contract_id)
->where('personnel_id', $personnel_id)
->where('deleted_at', 0)
->find();
if (empty($contractSign)) {
Db::rollback();
$res['msg'] = '合同签订记录不存在';
return $res;
}
// 检查合同状态
if ($contractSign['status'] != 1) {
Db::rollback();
$res['msg'] = '合同状态不允许签订';
return $res;
}
// 检查是否已经签订
if (!empty($contractSign['sign_file'])) {
Db::rollback();
$res['msg'] = '合同已经签订,无需重复签订';
return $res;
}
// 生成签署后的合同文档
$generatedFile = null;
if ($sign_file) {
$generatedFile = $this->generateStaffSignedContract($contract_id, $personnel_id, $sign_file);
}
// 更新签订信息
$updateData = [
'sign_file' => $generatedFile ?: $sign_file,
'sign_time' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s')
];
if ($generatedFile) {
$updateData['signature_image'] = $sign_file;
}
$updateResult = ContractSign::where('id', $contractSign['id'])->update($updateData);
if (!$updateResult) {
Db::rollback();
$res['msg'] = '更新签订信息失败';
return $res;
}
// 提交事务
Db::commit();
$res = [
'code' => 1,
'msg' => '签订成功',
'data' => [
'contract_id' => $contract_id,
'sign_time' => $updateData['sign_time'],
'generated_file' => $generatedFile
]
];
} catch (\Exception $e) {
Db::rollback();
$res['msg'] = '签订合同异常:' . $e->getMessage();
}
return $res;
}
/**
* 获取合同签订状态
* @param array $where
* @return array
*/
public function getSignStatus(array $where)
{
$res = [
'code' => 0,
'msg' => '获取签订状态失败',
'data' => []
];
try {
$contract_id = $where['contract_id'] ?? 0;
$personnel_id = $where['personnel_id'] ?? 0;
if (empty($contract_id) || empty($personnel_id)) {
$res['msg'] = '参数错误';
return $res;
}
$contractSign = ContractSign::where('contract_id', $contract_id)
->where('personnel_id', $personnel_id)
->where('deleted_at', 0)
->field('id,sign_file,status,sign_time')
->find();
if (empty($contractSign)) {
$res['msg'] = '合同签订记录不存在';
return $res;
}
$signData = $contractSign->toArray();
// 判断签订状态
$signData['is_signed'] = !empty($signData['sign_file']);
$signData['can_sign'] = $signData['status'] == 1 && empty($signData['sign_file']);
$res = [
'code' => 1,
'msg' => '获取成功',
'data' => $signData
];
} catch (\Exception $e) {
$res['msg'] = '获取签订状态异常:' . $e->getMessage();
}
return $res;
}
/**
* 下载合同文件
* @param array $where
* @return array
*/
public function downloadContract(array $where)
{
$res = [
'code' => 0,
'msg' => '下载合同失败',
'data' => []
];
try {
$contract_id = $where['contract_id'] ?? 0;
$personnel_id = $where['personnel_id'] ?? 0;
if (empty($contract_id) || empty($personnel_id)) {
$res['msg'] = '参数错误';
return $res;
}
// 查询合同信息
$contractSign = ContractSign::alias('cs')
->join('school_contract c', 'cs.contract_id = c.id')
->where('cs.contract_id', $contract_id)
->where('cs.personnel_id', $personnel_id)
->where('cs.deleted_at', 0)
->where('c.deleted_at', 0)
->field([
'cs.sign_file',
'c.contract_template',
'c.contract_name'
])
->find();
if (empty($contractSign)) {
$res['msg'] = '合同不存在或无权限访问';
return $res;
}
$contractData = $contractSign->toArray();
// 返回下载信息
$downloadData = [
'contract_name' => $contractData['contract_name'],
'sign_file' => $contractData['sign_file'],
'contract_template' => $contractData['contract_template'],
'download_url' => !empty($contractData['sign_file']) ? $contractData['sign_file'] : $contractData['contract_template']
];
$res = [
'code' => 1,
'msg' => '获取下载信息成功',
'data' => $downloadData
];
} catch (\Exception $e) {
$res['msg'] = '获取下载信息异常:' . $e->getMessage();
}
return $res;
}
/**
* 生成员工签署后的合同文档
* @param int $contractId
* @param int $personnelId
* @param string $signatureImage
* @return string|null
*/
private function generateStaffSignedContract($contractId, $personnelId, $signatureImage)
{
try {
// 获取合同模板信息
$contract = Contract::find($contractId);
if (!$contract || !$contract['contract_template']) {
return null;
}
// 构建模板路径
$templatePath = public_path() . '/upload/' . $contract['contract_template'];
if (!file_exists($templatePath)) {
return null;
}
// 生成输出文件名和路径
$outputFileName = 'staff_signed_contract_' . $personnelId . '_' . $contractId . '_' . date('YmdHis') . '.docx';
$outputRelPath = 'contracts/staff_signed/' . date('Y/m/') . $outputFileName;
$outputFullPath = public_path() . '/upload/' . $outputRelPath;
// 确保目录存在
$outputDir = dirname($outputFullPath);
if (!is_dir($outputDir)) {
mkdir($outputDir, 0755, true);
}
// 获取员工信息并准备填充数据
$fillData = $this->prepareStaffFillData($contractId, $personnelId);
// 使用PhpWord处理模板
$templateProcessor = new TemplateProcessor($templatePath);
// 填充文本数据
foreach ($fillData as $placeholder => $value) {
$templateProcessor->setValue($placeholder, $value);
}
// 处理签名图片
if ($signatureImage) {
// 处理签名图片
$signImagePath = $this->processStaffSignatureImage($signatureImage);
// 使用ContractSign服务插入签名
$contractSignService = new ContractSignService();
$contractSignService->setSign($templatePath, $outputFullPath, $signImagePath, '员工签名');
// 清理临时文件
if (file_exists($signImagePath)) {
unlink($signImagePath);
}
} else {
// 没有签名时直接保存
$templateProcessor->saveAs($outputFullPath);
}
return $outputRelPath;
} catch (\Exception $e) {
return null;
}
}
/**
* 准备员工填充数据
* @param int $contractId
* @param int $personnelId
* @return array
*/
private function prepareStaffFillData($contractId, $personnelId)
{
$fillData = [];
try {
// 获取员工信息
$personnel = Db::table('school_personnel')->where('id', $personnelId)->find();
if ($personnel) {
$fillData['员工姓名'] = $personnel['name'] ?? '';
$fillData['员工编号'] = $personnel['employee_number'] ?? '';
$fillData['员工电话'] = $personnel['phone'] ?? '';
$fillData['员工邮箱'] = $personnel['email'] ?? '';
$fillData['入职时间'] = $personnel['join_time'] ?? '';
}
// 添加系统信息
$fillData['签署日期'] = date('Y-m-d');
$fillData['签署时间'] = date('Y-m-d H:i:s');
$fillData['合同编号'] = $contractId . date('Ymd') . $personnelId;
} catch (\Exception $e) {
// 记录错误日志但不中断流程
}
return $fillData;
}
/**
* 处理员工签名图片
* @param string $signatureImage
* @return string
*/
private function processStaffSignatureImage($signatureImage)
{
$tempImagePath = public_path() . '/upload/temp_staff_sign_' . date('YmdHis') . '_' . mt_rand(1000, 9999) . '.png';
if (strpos($signatureImage, 'data:image') === 0) {
// Base64图片
$imageData = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $signatureImage));
if ($imageData !== false) {
file_put_contents($tempImagePath, $imageData);
}
} elseif (filter_var($signatureImage, FILTER_VALIDATE_URL)) {
// URL图片
$imageContent = file_get_contents($signatureImage);
if ($imageContent !== false) {
file_put_contents($tempImagePath, $imageContent);
}
} else {
// 本地路径
$localPath = public_path() . '/upload/' . ltrim($signatureImage, '/');
if (file_exists($localPath)) {
copy($localPath, $tempImagePath);
}
}
return $tempImagePath;
}
}