mirror of
https://gitee.com/ShopeX/OMS
synced 2026-04-04 22:36:52 +08:00
1. 【新增】售后单售后原因类型支持搜索
2. 【新增】手工创建订单折扣可输入正数 3. 【优化】盘点申请单确认 4. 【修复】采购退货单模拟出库失败问题 5. 【新增】订单金额客户实付与结算金额 6. 【优化】仓库发货统计报表物料名称显示 7. 【优化】自有仓储虚拟发货逻辑 8. 【修复】基础物料分类管理问题
This commit is contained in:
321
app/ticket/controller/admin/workflow/case.php
Normal file
321
app/ticket/controller/admin/workflow/case.php
Normal file
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
/**
|
||||
* 审批流实例控制器
|
||||
*
|
||||
* @author shopex开发团队
|
||||
* @version 2025.07.10
|
||||
*/
|
||||
class ticket_ctl_admin_workflow_case extends desktop_controller {
|
||||
var $title = '审批流实例列表';
|
||||
var $workground = 'ticket_center';
|
||||
private $_appName = 'ticket';
|
||||
|
||||
private $_mdl = null; //model类
|
||||
private $_primary_id = null; //主键ID字段名
|
||||
private $_primary_bn = null; //单据编号字段名
|
||||
|
||||
/**
|
||||
* Lib对象
|
||||
*/
|
||||
protected $_workflowCaseLib = null;
|
||||
|
||||
public function __construct($app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
|
||||
$this->_mdl = app::get($this->_appName)->model('workflow_case');
|
||||
$this->_workflowCaseLib = kernel::single('ticket_workflow_case');
|
||||
|
||||
//primary_id
|
||||
$this->_primary_id = 'id';
|
||||
|
||||
//primary_bn
|
||||
$this->_primary_bn = 'case_bn';
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页面
|
||||
*/
|
||||
public function index() {
|
||||
$user = kernel::single('desktop_user');
|
||||
$actions = array();
|
||||
|
||||
//filter
|
||||
$base_filter = [];
|
||||
|
||||
//button
|
||||
$buttonList = array();
|
||||
|
||||
//view
|
||||
$_GET['view'] = (empty($_GET['view']) ? '0' : $_GET['view']);
|
||||
switch ($_GET['view'])
|
||||
{
|
||||
case '0':
|
||||
//--
|
||||
}
|
||||
|
||||
//params
|
||||
$orderby = 'id DESC';
|
||||
$params = array(
|
||||
'title' => $this->title,
|
||||
'base_filter' => $base_filter,
|
||||
'actions'=> $actions,
|
||||
'use_buildin_new_dialog' => false,
|
||||
'use_buildin_set_tag' => false,
|
||||
'use_buildin_recycle' => false,
|
||||
'use_buildin_export' => false,
|
||||
'use_buildin_import' => false,
|
||||
'use_buildin_filter' => true,
|
||||
'orderBy' => $orderby,
|
||||
);
|
||||
$this->finder('ticket_mdl_workflow_case', $params);
|
||||
}
|
||||
|
||||
public function _views()
|
||||
{
|
||||
//filter
|
||||
$base_filter = [];
|
||||
|
||||
//menu
|
||||
$sub_menu = array(
|
||||
0 => array('label'=>app::get('base')->_('全部'), 'filter'=>$base_filter, 'optional'=>false),
|
||||
1 => array('label'=>app::get('base')->_('待审批'), 'filter'=>['status'=>['pending','processing','approved'], 'current_node_type'=>['start','approval']], 'optional'=>false),
|
||||
2 => array('label'=>app::get('base')->_('已完成'), 'filter'=>['current_node_type'=>'end'], 'optional'=>false),
|
||||
3 => array('label'=>app::get('base')->_('取消'), 'filter'=>['status'=>['rejected','cancelled']], 'optional'=>false),
|
||||
);
|
||||
|
||||
foreach($sub_menu as $k => $v)
|
||||
{
|
||||
if (isset($v['filter'])){
|
||||
$v['filter'] = array_merge($base_filter, $v['filter']);
|
||||
}
|
||||
|
||||
$sub_menu[$k]['filter'] = $v['filter'] ? $v['filter'] : null;
|
||||
$sub_menu[$k]['href'] = 'index.php?app='. $_GET['app'] .'&ctl='.$_GET['ctl'].'&act='.$_GET['act'].'&view='.$k;
|
||||
|
||||
//第一个TAB菜单没有数据时显示全部
|
||||
if($k == 0){
|
||||
//count
|
||||
$sub_menu[$k]['addon'] = $this->_mdl->count($v['filter']);
|
||||
if($sub_menu[$k]['addon'] == 0){
|
||||
unset($sub_menu[$k]);
|
||||
}
|
||||
}else{
|
||||
//count
|
||||
$sub_menu[$k]['addon'] = $this->_mdl->viewcount($v['filter']);
|
||||
}
|
||||
}
|
||||
|
||||
return $sub_menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核页面
|
||||
*/
|
||||
public function audit($id)
|
||||
{
|
||||
$nodeLib = kernel::single('ticket_workflow_node');
|
||||
|
||||
// info
|
||||
$row = $this->_mdl->dump($id);
|
||||
|
||||
// check
|
||||
if(empty($row)){
|
||||
die('数据不存在,请检查!');
|
||||
}
|
||||
|
||||
if(empty($row['items_context'])){
|
||||
die('审批流实例没有赠品信息,请检查!');
|
||||
}
|
||||
|
||||
if($row['current_node_type'] == 'end'){
|
||||
die('审批流已经结束,不能操作!');
|
||||
}elseif(in_array($row['status'], ['rejected','cancelled'])){
|
||||
die('审批已拒绝或取消,不能操作!');
|
||||
}
|
||||
|
||||
// order info
|
||||
$result = $this->_workflowCaseLib->getOrderDetails($row);
|
||||
if($result['rsp'] != 'succ'){
|
||||
die($result['error_msg']);
|
||||
}
|
||||
|
||||
$orderInfo = $result['data'];
|
||||
|
||||
// addGiftList
|
||||
$addGiftList = $orderInfo['addGiftList'];
|
||||
|
||||
// 当前节点
|
||||
$currentNode = $nodeLib->getCurrentNode($row['current_node_id']);
|
||||
|
||||
$this->pagedata['currentNode'] = $currentNode;
|
||||
$this->pagedata['addGiftList'] = $addGiftList;
|
||||
$this->pagedata['orderInfo'] = $orderInfo;
|
||||
$this->pagedata['data'] = $row;
|
||||
$this->page('admin/workflow/case/audit.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* 审核确认
|
||||
*/
|
||||
public function do_audit() {
|
||||
$this->begin($this->url.'&act=index');
|
||||
|
||||
$data = $_POST;
|
||||
$error_msg = '';
|
||||
|
||||
// check
|
||||
$checkResult = $this->_workflowCaseLib->checkAuditParams($data);
|
||||
if($checkResult['rsp'] != 'succ'){
|
||||
$error_msg = '审批检测失败:'. $checkResult['error_msg'];
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
// save
|
||||
$saveResult = $this->_workflowCaseLib->processAudit($data, $error_msg);
|
||||
if($saveResult['rsp'] != 'succ'){
|
||||
$error_msg = '审批保存失败:'. $error_msg;
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
$this->end(true, '操作成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建订单赠品审批实例
|
||||
*/
|
||||
public function create_gift_approval() {
|
||||
$this->begin($this->url.'&act=index');
|
||||
|
||||
$data = $_POST;
|
||||
|
||||
// check
|
||||
$checkResult = $this->_workflowCaseLib->checkCreateGiftApprovalParams($data);
|
||||
if($checkResult['rsp'] != 'succ'){
|
||||
$error_msg = '检查失败:'. $checkResult['error_msg'];
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
// create
|
||||
$createResult = $this->_workflowCaseLib->createGiftApprovalCase($data, $error_msg);
|
||||
if($createResult['rsp'] != 'succ'){
|
||||
$error_msg = '创建失败:'. $error_msg;
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
$this->end(true, '审批实例创建成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取待审批列表
|
||||
*/
|
||||
public function get_pending_list() {
|
||||
$user = kernel::single('desktop_user');
|
||||
$user_id = $user->get_id();
|
||||
|
||||
$result = $this->_workflowCaseLib->getPendingCasesByUser($user_id);
|
||||
|
||||
$this->pagedata['pending_list'] = $result['data'];
|
||||
$this->page('admin/workflow/case/pending_list.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批流程详情
|
||||
*/
|
||||
public function detail($id) {
|
||||
// info
|
||||
$row = $this->_mdl->dump($id);
|
||||
|
||||
// check
|
||||
if(empty($row)){
|
||||
die('数据不存在,请检查!');
|
||||
}
|
||||
|
||||
// get approval records
|
||||
$recordResult = $this->_workflowCaseLib->getApprovalRecords($id);
|
||||
if($recordResult['rsp'] != 'succ'){
|
||||
die($recordResult['error_msg']);
|
||||
}
|
||||
|
||||
// order info
|
||||
$orderResult = $this->_workflowCaseLib->getOrderDetails($row);
|
||||
if($orderResult['rsp'] != 'succ'){
|
||||
die($orderResult['error_msg']);
|
||||
}
|
||||
|
||||
$this->pagedata['data'] = $row;
|
||||
$this->pagedata['records'] = $recordResult['data'];
|
||||
$this->pagedata['orderInfo'] = $orderResult['data'];
|
||||
$this->page('admin/workflow/case/detail.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消审批
|
||||
*/
|
||||
public function cancel_approval() {
|
||||
$this->begin($this->url.'&act=index');
|
||||
|
||||
$data = $_POST;
|
||||
|
||||
// check
|
||||
$checkResult = $this->_workflowCaseLib->checkCancelParams($data);
|
||||
if($checkResult['rsp'] != 'succ'){
|
||||
$error_msg = '检查失败:'. $checkResult['error_msg'];
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
// cancel
|
||||
$cancelResult = $this->_workflowCaseLib->cancelApproval($data, $error_msg);
|
||||
if($cancelResult['rsp'] != 'succ'){
|
||||
$error_msg = '取消失败:'. $error_msg;
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
$this->end(true, '审批已取消');
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新提交审批
|
||||
*/
|
||||
public function resubmit_approval() {
|
||||
$this->begin($this->url.'&act=index');
|
||||
|
||||
$data = $_POST;
|
||||
|
||||
// check
|
||||
$checkResult = $this->_workflowCaseLib->checkResubmitParams($data);
|
||||
if($checkResult['rsp'] != 'succ'){
|
||||
$error_msg = '检查失败:'. $checkResult['error_msg'];
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
// resubmit
|
||||
$resubmitResult = $this->_workflowCaseLib->resubmitApproval($data, $error_msg);
|
||||
if($resubmitResult['rsp'] != 'succ'){
|
||||
$error_msg = '重新提交失败:'. $error_msg;
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
$this->end(true, '审批已重新提交');
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出审批记录
|
||||
*/
|
||||
public function export_records() {
|
||||
$data = $_GET;
|
||||
|
||||
$result = $this->_workflowCaseLib->exportApprovalRecords($data);
|
||||
if($result['rsp'] != 'succ'){
|
||||
die($result['error_msg']);
|
||||
}
|
||||
|
||||
// 输出CSV文件
|
||||
$filename = 'approval_records_' . date('YmdHis') . '.csv';
|
||||
header('Content-Type: application/csv');
|
||||
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
||||
|
||||
echo $result['data'];
|
||||
exit;
|
||||
}
|
||||
}
|
||||
448
app/ticket/controller/admin/workflow/flow.php
Normal file
448
app/ticket/controller/admin/workflow/flow.php
Normal file
@@ -0,0 +1,448 @@
|
||||
<?php
|
||||
/**
|
||||
* 审批流API控制器
|
||||
*
|
||||
* @author shopex开发团队
|
||||
* @version 2025.07.10
|
||||
*/
|
||||
class ticket_ctl_admin_workflow_flow extends desktop_controller {
|
||||
var $title = '审批流API';
|
||||
var $workground = 'ticket_center';
|
||||
|
||||
public function __construct($app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审批流场景类型列表
|
||||
*/
|
||||
public function getSceneTypeList() {
|
||||
try {
|
||||
$templateMdl = app::get('ticket')->model('workflow_template');
|
||||
|
||||
// 定义场景类型(写死)
|
||||
$sceneTypes = [
|
||||
[
|
||||
'scene_type' => 'add_gift',
|
||||
'scene_name' => '加赠',
|
||||
'scene_memo' => '加赠商品审批流程'
|
||||
]
|
||||
];
|
||||
|
||||
$sceneList = [];
|
||||
foreach($sceneTypes as $sceneType){
|
||||
// 查询该场景类型的模板配置
|
||||
$templateInfo = $templateMdl->dump(['scene_type' => $sceneType['scene_type']], 'id,is_enabled');
|
||||
|
||||
// 根据查询结果设置status
|
||||
if(empty($templateInfo)){
|
||||
// 没有数据,未配置
|
||||
$status = '0';
|
||||
} elseif($templateInfo['is_enabled'] == 'true'){
|
||||
// 已配置
|
||||
$status = '1';
|
||||
} else {
|
||||
// 已禁用
|
||||
$status = '2';
|
||||
}
|
||||
|
||||
$sceneList[] = [
|
||||
'scene_type' => $sceneType['scene_type'],
|
||||
'scene_name' => $sceneType['scene_name'],
|
||||
'scene_memo' => $sceneType['scene_memo'],
|
||||
'status' => $status // 0(未配置),1(已配置),2(已禁用)
|
||||
];
|
||||
}
|
||||
|
||||
$this->returnJson($sceneList, true, '获取审批流场景类型列表成功');
|
||||
} catch (Exception $e) {
|
||||
$this->returnJson([], false, '获取审批流场景类型列表失败:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据场景类型获取审批流配置
|
||||
*/
|
||||
public function getWorkflowBySceneType() {
|
||||
try {
|
||||
// 获取JSON数据
|
||||
$input = file_get_contents('php://input');
|
||||
$data = json_decode($input, true);
|
||||
|
||||
// 如果JSON解析失败,尝试从$_POST获取
|
||||
if(empty($data)){
|
||||
$data = $_POST;
|
||||
}
|
||||
|
||||
$scene_type = $data['scene_type'] ?? '';
|
||||
|
||||
if(empty($scene_type)){
|
||||
$this->returnJson([], false, '场景类型不能为空');
|
||||
}
|
||||
|
||||
// 查询模板信息
|
||||
$templateMdl = app::get('ticket')->model('workflow_template');
|
||||
$templateInfo = $templateMdl->dump(['scene_type' => $scene_type], '*');
|
||||
|
||||
if(empty($templateInfo)){
|
||||
$this->returnJson(['nodes'=>[]], true, '获取审批流配置成功');
|
||||
}
|
||||
|
||||
// 查询节点信息
|
||||
$nodeMdl = app::get('ticket')->model('workflow_node');
|
||||
$nodeList = $nodeMdl->getList('*', ['template_id' => $templateInfo['id']], 0, -1, 'step_order ASC');
|
||||
|
||||
// 格式化节点数据
|
||||
$nodes = [];
|
||||
foreach($nodeList as $node){
|
||||
$nodes[] = [
|
||||
'node_id' => $node['id'],
|
||||
'node_name' => $node['node_name'],
|
||||
'node_type' => $node['node_type'],
|
||||
'step_order' => $node['step_order'],
|
||||
'assignee_type' => $node['assignee_type'],
|
||||
'assignee_id' => $node['assignee_id'],
|
||||
'assignee_name' => $node['assignee_name']
|
||||
];
|
||||
}
|
||||
|
||||
// 组装返回数据
|
||||
$result = [
|
||||
'template_id' => $templateInfo['id'],
|
||||
'template_bn' => $templateInfo['template_bn'],
|
||||
'template_name' => $templateInfo['template_name'],
|
||||
'scene_type' => $templateInfo['scene_type'],
|
||||
'description' => $templateInfo['description'],
|
||||
'version' => '1', // 固定版本号
|
||||
'status' => $templateInfo['is_enabled'] == 'true' ? '1' : '2', // 1已配置,2已禁用
|
||||
'nodes' => $nodes
|
||||
];
|
||||
|
||||
$this->returnJson($result, true, '获取审批流配置成功');
|
||||
} catch (Exception $e) {
|
||||
$this->returnJson([], false, '获取审批流配置失败:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存审批流(包含模板和节点信息)
|
||||
* 支持新建和更新两种场景
|
||||
*/
|
||||
public function saveWorkflow() {
|
||||
try {
|
||||
// 获取JSON数据
|
||||
$input = file_get_contents('php://input');
|
||||
$data = json_decode($input, true);
|
||||
|
||||
// 如果JSON解析失败,尝试从$_POST获取
|
||||
if(empty($data)){
|
||||
$data = $_POST;
|
||||
}
|
||||
|
||||
// 验证必要参数
|
||||
if(empty($data['template_name'])){
|
||||
$this->returnJson([], false, '模板名称不能为空');
|
||||
}
|
||||
|
||||
if(empty($data['scene_type'])){
|
||||
$this->returnJson([], false, '场景类型不能为空');
|
||||
}
|
||||
|
||||
if(empty($data['nodes']) || !is_array($data['nodes'])){
|
||||
$this->returnJson([], false, '节点数据不能为空');
|
||||
}
|
||||
|
||||
$templateMdl = app::get('ticket')->model('workflow_template');
|
||||
$nodeMdl = app::get('ticket')->model('workflow_node');
|
||||
|
||||
// 开启事务
|
||||
$db = kernel::database();
|
||||
$tran = $db->beginTransaction();
|
||||
|
||||
// 处理status转is_enabled
|
||||
// status: 1启用, 2禁用 -> is_enabled: true启用, false禁用
|
||||
$is_enabled = 'true'; // 默认启用
|
||||
if(isset($data['status'])){
|
||||
$is_enabled = ($data['status'] == '1' || $data['status'] == 1) ? 'true' : 'false';
|
||||
} elseif(isset($data['is_enabled'])){
|
||||
$is_enabled = $data['is_enabled'];
|
||||
}
|
||||
|
||||
// 准备模板数据
|
||||
$templateData = [
|
||||
'template_name' => $data['template_name'],
|
||||
'scene_type' => $data['scene_type'],
|
||||
'description' => is_array($data['description']) ? implode('', $data['description']) : $data['description'],
|
||||
'is_enabled' => $is_enabled
|
||||
];
|
||||
|
||||
// 判断是新建还是更新
|
||||
$is_edit = !empty($data['template_id']);
|
||||
$old_template_data = null; // 用于存储更新前的数据
|
||||
|
||||
if(!$is_edit){
|
||||
// 新建模板
|
||||
// 生成模板编号
|
||||
$templateData['template_bn'] = 'TPL_' . strtoupper(uniqid());
|
||||
|
||||
$insertResult = $templateMdl->insert($templateData);
|
||||
if(!$insertResult){
|
||||
$db->rollBack();
|
||||
$this->returnJson([], false, '创建模板失败');
|
||||
}
|
||||
|
||||
$template_id = $templateData['id'];
|
||||
|
||||
// 新建时直接插入节点数据
|
||||
foreach($data['nodes'] as $nodeData){
|
||||
if(empty($nodeData['node_name']) || empty($nodeData['node_type'])){
|
||||
continue; // 跳过无效节点
|
||||
}
|
||||
|
||||
$insertNodeData = [
|
||||
'template_id' => $template_id,
|
||||
'node_name' => $nodeData['node_name'],
|
||||
'node_type' => $nodeData['node_type'],
|
||||
'step_order' => $nodeData['step_order'] ?? 1,
|
||||
'assignee_type' => $nodeData['assignee_type'] ?? 'user',
|
||||
'assignee_id' => $nodeData['assignee_id'] ?? 0,
|
||||
'assignee_name' => $nodeData['assignee_name'] ?? ''
|
||||
];
|
||||
|
||||
$insertResult = $nodeMdl->insert($insertNodeData);
|
||||
if(!$insertResult){
|
||||
$db->rollBack();
|
||||
$this->returnJson([], false, '插入节点数据失败');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 更新模板 - 先获取更新前的数据
|
||||
$template_id = $data['template_id'];
|
||||
$old_template_data = $templateMdl->dump(['id' => $template_id], '*, id as template_id');
|
||||
|
||||
// 获取更新前的节点数据
|
||||
$old_nodes = $nodeMdl->getList('*, id as node_id', ['template_id' => $template_id], 0, -1, 'step_order ASC');
|
||||
$old_template_data['nodes'] = $old_nodes;
|
||||
|
||||
$updateResult = $templateMdl->update($templateData, ['id' => $template_id]);
|
||||
if($updateResult === false){
|
||||
$db->rollBack();
|
||||
$this->returnJson([], false, '更新模板信息失败');
|
||||
}
|
||||
|
||||
// 精细处理节点更新
|
||||
$this->updateWorkflowNodes($template_id, $data['nodes'], $old_nodes, $db);
|
||||
}
|
||||
|
||||
// 提交事务
|
||||
$db->commit($tran);
|
||||
|
||||
// 记录操作日志
|
||||
$this->recordWorkflowLog($template_id, $data, $old_template_data, $is_edit);
|
||||
|
||||
$this->returnJson([], true, '保存审批流成功');
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->returnJson([], false, '保存审批流失败:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取审批人列表
|
||||
*/
|
||||
public function getAssigneeList() {
|
||||
try {
|
||||
// 获取JSON数据
|
||||
$input = file_get_contents('php://input');
|
||||
$data = json_decode($input, true);
|
||||
|
||||
// 如果JSON解析失败,尝试从$_POST获取
|
||||
if(empty($data)){
|
||||
$data = $_POST;
|
||||
}
|
||||
|
||||
$assignee_type = $data['assignee_type'] ?? 'user';
|
||||
|
||||
// 根据审批人类型返回不同数据
|
||||
if($assignee_type == 'user'){
|
||||
// 获取用户列表
|
||||
$userMdl = app::get('desktop')->model('users');
|
||||
$userList = $userMdl->getList('user_id,name', ['status'=>1], 0, -1);
|
||||
|
||||
// 格式化数据
|
||||
$assigneeList = [];
|
||||
foreach($userList as $user){
|
||||
$assigneeList[] = [
|
||||
'id' => $user['user_id'],
|
||||
'name' => $user['name']
|
||||
];
|
||||
}
|
||||
|
||||
$result = [
|
||||
'assignee' => $assigneeList
|
||||
];
|
||||
} elseif($assignee_type == 'role'){
|
||||
// 角色类型暂时返回空数组
|
||||
$result = [
|
||||
'assignee' => []
|
||||
];
|
||||
} elseif($assignee_type == 'dept'){
|
||||
// 部门类型暂时返回空数组
|
||||
$result = [
|
||||
'assignee' => []
|
||||
];
|
||||
} else {
|
||||
// 其他类型返回空数组
|
||||
$result = [
|
||||
'assignee' => []
|
||||
];
|
||||
}
|
||||
|
||||
$this->returnJson($result, true, '获取审批人列表成功');
|
||||
} catch (Exception $e) {
|
||||
$this->returnJson([], false, '获取审批人列表失败:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 精细处理节点更新(增删改)
|
||||
*/
|
||||
private function updateWorkflowNodes($template_id, $new_nodes, $old_nodes, $db)
|
||||
{
|
||||
$nodeMdl = app::get('ticket')->model('workflow_node');
|
||||
$caseMdl = app::get('ticket')->model('workflow_case');
|
||||
|
||||
// 将旧节点按node_id建立索引
|
||||
$old_nodes_map = [];
|
||||
foreach($old_nodes as $old_node){
|
||||
$old_nodes_map[$old_node['id']] = $old_node;
|
||||
}
|
||||
|
||||
// 将新节点按node_id建立索引(如果有node_id的话)
|
||||
$new_nodes_map = [];
|
||||
foreach($new_nodes as $new_node){
|
||||
if(!empty($new_node['node_id'])){
|
||||
$new_nodes_map[$new_node['node_id']] = $new_node;
|
||||
}
|
||||
}
|
||||
|
||||
// 1. 处理需要删除的节点
|
||||
$nodes_to_delete = [];
|
||||
foreach($old_nodes_map as $old_node_id => $old_node){
|
||||
if(!isset($new_nodes_map[$old_node_id])){
|
||||
$nodes_to_delete[] = $old_node_id;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查删除的节点是否被使用中
|
||||
if(!empty($nodes_to_delete)){
|
||||
$used_nodes = $caseMdl->getList('distinct current_node_id', [
|
||||
'template_id' => $template_id,
|
||||
'current_node_id|in' => $nodes_to_delete,
|
||||
'status|in' => ['pending', 'processing', 'approved']
|
||||
]);
|
||||
|
||||
if(!empty($used_nodes)){
|
||||
$db->rollBack();
|
||||
$used_node_ids = array_column($used_nodes, 'current_node_id');
|
||||
$used_node_names = [];
|
||||
foreach($used_node_ids as $used_node_id){
|
||||
$used_node_names[] = $old_nodes_map[$used_node_id]['node_name'] ?? '未知节点';
|
||||
}
|
||||
$this->returnJson([], false, "节点「" . implode('、', $used_node_names) . "」正在被审批流程使用中,无法删除");
|
||||
}
|
||||
|
||||
// 执行删除
|
||||
$deleteResult = $nodeMdl->delete(['id' => $nodes_to_delete]);
|
||||
if($deleteResult === false){
|
||||
$db->rollBack();
|
||||
$this->returnJson([], false, '删除节点失败');
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 处理需要更新的节点
|
||||
foreach($new_nodes_map as $node_id => $new_node){
|
||||
if(isset($old_nodes_map[$node_id])){
|
||||
// 更新节点
|
||||
$updateNodeData = [
|
||||
'node_name' => $new_node['node_name'],
|
||||
'node_type' => $new_node['node_type'],
|
||||
'step_order' => $new_node['step_order'] ?? 1,
|
||||
'assignee_type' => $new_node['assignee_type'] ?? 'user',
|
||||
'assignee_id' => $new_node['assignee_id'] ?? 0,
|
||||
'assignee_name' => $new_node['assignee_name'] ?? ''
|
||||
];
|
||||
|
||||
$updateResult = $nodeMdl->update($updateNodeData, ['id' => $node_id]);
|
||||
if($updateResult === false){
|
||||
$db->rollBack();
|
||||
$node_name = $new_node['node_name'] ?? '未知节点';
|
||||
$this->returnJson([], false, "更新节点「{$node_name}」失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 处理需要新增的节点
|
||||
foreach($new_nodes as $new_node){
|
||||
if(empty($new_node['node_id']) || !isset($old_nodes_map[$new_node['node_id']])){
|
||||
// 新增节点
|
||||
if(empty($new_node['node_name']) || empty($new_node['node_type'])){
|
||||
continue; // 跳过无效节点
|
||||
}
|
||||
|
||||
$insertNodeData = [
|
||||
'template_id' => $template_id,
|
||||
'node_name' => $new_node['node_name'],
|
||||
'node_type' => $new_node['node_type'],
|
||||
'step_order' => $new_node['step_order'] ?? 1,
|
||||
'assignee_type' => $new_node['assignee_type'] ?? 'user',
|
||||
'assignee_id' => $new_node['assignee_id'] ?? 0,
|
||||
'assignee_name' => $new_node['assignee_name'] ?? ''
|
||||
];
|
||||
|
||||
$insertResult = $nodeMdl->insert($insertNodeData);
|
||||
if(!$insertResult){
|
||||
$db->rollBack();
|
||||
$this->returnJson([], false, '插入新节点数据失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录审批流操作日志
|
||||
*/
|
||||
private function recordWorkflowLog($template_id, $data, $old_template_data, $is_edit = false)
|
||||
{
|
||||
// 获取操作日志模型
|
||||
$omeLogMdl = app::get('ome')->model('operation_log');
|
||||
|
||||
// 准备日志数据
|
||||
$log_key = $is_edit ? 'ticket_workflow_edit@ticket' : 'ticket_workflow_add@ticket';
|
||||
$operation_type = $is_edit ? '编辑' : '新建';
|
||||
|
||||
// 构建memo信息
|
||||
$memo = "审批流{$operation_type}:模板名称={$data['template_name']},场景类型={$data['scene_type']},节点数量=" . count($data['nodes']);
|
||||
|
||||
// 记录日志
|
||||
$log_id = $omeLogMdl->write_log($log_key, $template_id, $memo);
|
||||
|
||||
// 生成操作快照
|
||||
if ($log_id) {
|
||||
$shootMdl = app::get('ome')->model('operation_log_snapshoot');
|
||||
|
||||
// snapshoot是更新前的数据,updated是更新后的数据
|
||||
$snapshoot = $is_edit && $old_template_data ? json_encode($old_template_data, JSON_UNESCAPED_UNICODE) : '';
|
||||
$updated = json_encode($data, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
$tmp = [
|
||||
'log_id' => $log_id,
|
||||
'snapshoot' => $snapshoot,
|
||||
'updated' => $updated
|
||||
];
|
||||
$shootMdl->insert($tmp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
172
app/ticket/controller/admin/workflow/node.php
Normal file
172
app/ticket/controller/admin/workflow/node.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
/**
|
||||
* 审批流节点控制器
|
||||
*
|
||||
* @author shopex开发团队
|
||||
* @version 2025.07.10
|
||||
*/
|
||||
class ticket_ctl_admin_workflow_node extends desktop_controller {
|
||||
var $title = '审批流节点列表';
|
||||
var $workground = 'ticket_center';
|
||||
private $_appName = 'ticket';
|
||||
|
||||
private $_mdl = null; //model类
|
||||
private $_primary_id = null; //主键ID字段名
|
||||
private $_primary_bn = null; //单据编号字段名
|
||||
|
||||
/**
|
||||
* Lib对象
|
||||
*/
|
||||
protected $_workflowNodeLib = null;
|
||||
|
||||
public function __construct($app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
|
||||
$this->_mdl = app::get($this->_appName)->model('workflow_node');
|
||||
$this->_workflowNodeLib = kernel::single('ticket_workflow_node');
|
||||
|
||||
//primary_id
|
||||
$this->_primary_id = 'id';
|
||||
|
||||
//primary_bn
|
||||
$this->_primary_bn = 'node_name';
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页面
|
||||
*/
|
||||
public function index() {
|
||||
$user = kernel::single('desktop_user');
|
||||
$actions = array();
|
||||
|
||||
//filter
|
||||
$base_filter = [];
|
||||
|
||||
//button
|
||||
$buttonList = array();
|
||||
$buttonList['add'] = [
|
||||
'label' => '新增',
|
||||
'href' => $this->url.'&act=add'
|
||||
];
|
||||
|
||||
//view
|
||||
$_GET['view'] = (empty($_GET['view']) ? '0' : $_GET['view']);
|
||||
switch ($_GET['view'])
|
||||
{
|
||||
case '0':
|
||||
// 新建
|
||||
if($user->has_permission('ticket_workflow_node_operate')){
|
||||
$actions[] = $buttonList['add'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//params
|
||||
$orderby = 'template_id ASC, step_order ASC';
|
||||
$params = array(
|
||||
'title' => $this->title,
|
||||
'base_filter' => $base_filter,
|
||||
'actions'=> $actions,
|
||||
'use_buildin_new_dialog' => false,
|
||||
'use_buildin_set_tag' => false,
|
||||
'use_buildin_recycle' => false,
|
||||
'use_buildin_export' => false,
|
||||
'use_buildin_import' => false,
|
||||
'use_buildin_filter' => true,
|
||||
'orderBy' => $orderby,
|
||||
);
|
||||
$this->finder('ticket_mdl_workflow_node', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加页面
|
||||
*/
|
||||
public function add() {
|
||||
$nodeMdl = app::get('ticket')->model('workflow_node');
|
||||
$templateLib = kernel::single('ticket_workflow_template');
|
||||
$nodeLib = kernel::single('ticket_workflow_node');
|
||||
|
||||
// 审批模板列表
|
||||
$templateList = $templateLib->getTemplateList();
|
||||
|
||||
// 节点类型列表
|
||||
$noteTypeList = $nodeMdl->getNodeTypes();
|
||||
|
||||
// 审批人类型列表
|
||||
$assigneeTypeList = $nodeMdl->getAssigneeTypes();
|
||||
|
||||
// 操作员列表
|
||||
$userList = $nodeLib->getOperatorList();
|
||||
|
||||
$this->pagedata['templateList'] = $templateList;
|
||||
$this->pagedata['noteTypeList'] = $noteTypeList;
|
||||
$this->pagedata['assigneeTypeList'] = $assigneeTypeList;
|
||||
$this->pagedata['userList'] = $userList;
|
||||
$this->pagedata['data'] = [];
|
||||
|
||||
$this->page('admin/workflow/node/add.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑页面
|
||||
*/
|
||||
public function edit($id) {
|
||||
$nodeMdl = app::get('ticket')->model('workflow_node');
|
||||
$templateLib = kernel::single('ticket_workflow_template');
|
||||
$nodeLib = kernel::single('ticket_workflow_node');
|
||||
|
||||
// info
|
||||
$data = $nodeMdl->dump($id);
|
||||
if(empty($data)){
|
||||
$error_msg = '数据不存在,请检查';
|
||||
die($error_msg);
|
||||
}
|
||||
|
||||
// 审批模板列表
|
||||
$templateList = $templateLib->getTemplateList();
|
||||
|
||||
// 节点类型列表
|
||||
$noteTypeList = $nodeMdl->getNodeTypes();
|
||||
|
||||
// 审批人类型列表
|
||||
$assigneeTypeList = $nodeMdl->getAssigneeTypes();
|
||||
|
||||
// 操作员列表
|
||||
$userList = $nodeLib->getOperatorList();
|
||||
|
||||
$this->pagedata['templateList'] = $templateList;
|
||||
$this->pagedata['noteTypeList'] = $noteTypeList;
|
||||
$this->pagedata['assigneeTypeList'] = $assigneeTypeList;
|
||||
$this->pagedata['userList'] = $userList;
|
||||
$this->pagedata['data'] = $data;
|
||||
|
||||
$this->page('admin/workflow/node/add.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
*/
|
||||
public function save() {
|
||||
$this->begin($this->url.'&act=index');
|
||||
|
||||
// post
|
||||
$data = $_POST;
|
||||
|
||||
// check
|
||||
$checkResult = kernel::single('ticket_workflow_node')->checkParams($data);
|
||||
if($checkResult['rsp'] != 'succ'){
|
||||
$error_msg = '检查失败:'. $checkResult['error_msg'];
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
// save
|
||||
$saveResult = kernel::single('ticket_workflow_node')->saveData($data, $error_msg);
|
||||
if($saveResult['rsp'] != 'succ'){
|
||||
$error_msg = '保存失败:'. $error_msg;
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
$this->end(true, '操作成功');
|
||||
}
|
||||
}
|
||||
78
app/ticket/controller/admin/workflow/record.php
Normal file
78
app/ticket/controller/admin/workflow/record.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/**
|
||||
* 审批流记录控制器
|
||||
*
|
||||
* @author shopex开发团队
|
||||
* @version 2025.07.10
|
||||
*/
|
||||
class ticket_ctl_admin_workflow_record extends desktop_controller {
|
||||
var $title = '审批流记录列表';
|
||||
var $workground = 'ticket_center';
|
||||
private $_appName = 'ticket';
|
||||
|
||||
private $_mdl = null; //model类
|
||||
private $_primary_id = null; //主键ID字段名
|
||||
private $_primary_bn = null; //单据编号字段名
|
||||
|
||||
/**
|
||||
* Lib对象
|
||||
*/
|
||||
protected $_workflowRecordLib = null;
|
||||
|
||||
public function __construct($app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
|
||||
$this->_mdl = app::get($this->_appName)->model('workflow_record');
|
||||
$this->_workflowRecordLib = kernel::single('ticket_workflow_record');
|
||||
|
||||
//primary_id
|
||||
$this->_primary_id = 'id';
|
||||
|
||||
//primary_bn
|
||||
$this->_primary_bn = 'id';
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页面
|
||||
*/
|
||||
public function index() {
|
||||
$user = kernel::single('desktop_user');
|
||||
$actions = array();
|
||||
|
||||
//filter
|
||||
$base_filter = [];
|
||||
|
||||
//button
|
||||
$buttonList = array();
|
||||
$buttonList['add'] = [
|
||||
'label' => '新增',
|
||||
'href' => $this->url.'&act=add'
|
||||
];
|
||||
|
||||
//view
|
||||
$_GET['view'] = (empty($_GET['view']) ? '0' : $_GET['view']);
|
||||
switch ($_GET['view'])
|
||||
{
|
||||
case '0':
|
||||
//--
|
||||
break;
|
||||
}
|
||||
|
||||
//params
|
||||
$orderby = 'id DESC';
|
||||
$params = array(
|
||||
'title' => $this->title,
|
||||
'base_filter' => $base_filter,
|
||||
'actions'=> $actions,
|
||||
'use_buildin_new_dialog' => false,
|
||||
'use_buildin_set_tag' => false,
|
||||
'use_buildin_recycle' => false,
|
||||
'use_buildin_export' => false,
|
||||
'use_buildin_import' => false,
|
||||
'use_buildin_filter' => true,
|
||||
'orderBy' => $orderby,
|
||||
);
|
||||
$this->finder('ticket_mdl_workflow_record', $params);
|
||||
}
|
||||
}
|
||||
127
app/ticket/controller/admin/workflow/template.php
Normal file
127
app/ticket/controller/admin/workflow/template.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
* 审批流模板控制器
|
||||
*
|
||||
* @author shopex开发团队
|
||||
* @version 2025.07.10
|
||||
*/
|
||||
class ticket_ctl_admin_workflow_template extends desktop_controller {
|
||||
var $title = '审批流模板列表';
|
||||
var $workground = 'ticket_center';
|
||||
private $_appName = 'ticket';
|
||||
|
||||
private $_mdl = null; //model类
|
||||
private $_primary_id = null; //主键ID字段名
|
||||
private $_primary_bn = null; //单据编号字段名
|
||||
|
||||
/**
|
||||
* Lib对象
|
||||
*/
|
||||
protected $_workflowTemplateLib = null;
|
||||
|
||||
public function __construct($app)
|
||||
{
|
||||
parent::__construct($app);
|
||||
|
||||
$this->_mdl = app::get($this->_appName)->model('workflow_template');
|
||||
$this->_workflowTemplateLib = kernel::single('ticket_workflow_template');
|
||||
|
||||
//primary_id
|
||||
$this->_primary_id = 'id';
|
||||
|
||||
//primary_bn
|
||||
$this->_primary_bn = 'template_bn';
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表页面
|
||||
*/
|
||||
public function index() {
|
||||
$user = kernel::single('desktop_user');
|
||||
$actions = array();
|
||||
|
||||
//filter
|
||||
$base_filter = [];
|
||||
|
||||
//button
|
||||
$buttonList = array();
|
||||
$buttonList['add'] = [
|
||||
'label' => '新增',
|
||||
'href' => $this->url.'&act=add'
|
||||
];
|
||||
|
||||
//view
|
||||
$_GET['view'] = (empty($_GET['view']) ? '0' : $_GET['view']);
|
||||
switch ($_GET['view'])
|
||||
{
|
||||
case '0':
|
||||
// 新建
|
||||
if($user->has_permission('ticket_workflow_template_operate')){
|
||||
$actions[] = $buttonList['add'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//params
|
||||
$orderby = 'id DESC';
|
||||
$params = array(
|
||||
'title' => $this->title,
|
||||
'base_filter' => $base_filter,
|
||||
'actions'=> $actions,
|
||||
'use_buildin_new_dialog' => false,
|
||||
'use_buildin_set_tag' => false,
|
||||
'use_buildin_recycle' => false,
|
||||
'use_buildin_export' => false,
|
||||
'use_buildin_import' => false,
|
||||
'use_buildin_filter' => true,
|
||||
'orderBy' => $orderby,
|
||||
);
|
||||
$this->finder('ticket_mdl_workflow_template', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加页面
|
||||
*/
|
||||
public function add() {
|
||||
$this->pagedata['data'] = [];
|
||||
$this->page('admin/workflow/template/add.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑页面
|
||||
*/
|
||||
public function edit($id) {
|
||||
$model = app::get('ticket')->model('workflow_template');
|
||||
$row = $model->dump($id);
|
||||
|
||||
$this->pagedata['data'] = $row;
|
||||
$this->page('admin/workflow/template/add.html');
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据
|
||||
*/
|
||||
public function save() {
|
||||
$this->begin($this->url.'&act=index');
|
||||
|
||||
// post
|
||||
$data = $_POST;
|
||||
$error_msg = '';
|
||||
|
||||
// check
|
||||
$checkResult = kernel::single('ticket_workflow_template')->checkParams($data);
|
||||
if($checkResult['rsp'] != 'succ'){
|
||||
$error_msg = '检查失败:'. $checkResult['error_msg'];
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
// save
|
||||
$saveResult = kernel::single('ticket_workflow_template')->saveData($data, $error_msg);
|
||||
if($saveResult['rsp'] != 'succ'){
|
||||
$error_msg = '保存失败:'. $error_msg;
|
||||
$this->end(false, $error_msg);
|
||||
}
|
||||
|
||||
$this->end(true, '操作成功');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user