工作流合并

This commit is contained in:
gwokwong 2023-05-26 14:19:36 +08:00
commit 18280b4ff9
53 changed files with 4298 additions and 73 deletions

View File

@ -25,6 +25,7 @@ use Arr;
use Cache;
use Captcha;
use Carbon\Carbon;
use Hedeqiang\UMeng\Facades\Push;
use Request;
/**
@ -719,7 +720,16 @@ class UsersController extends AbstractController
$query->where("department", "")->orWhere("department", ",,");
});
} else {
$builder->where("department", "like", "%,{$keys['department']},%");
// 关联user_departments表中owner_userid查询出负责人重新排序部门负责人始终在前面
$builder->where(function($query) use ($keys) {
$query->where("department", "like", "%,{$keys['department']},%");
$query->orWhereIn('userid', function ($query) use ($keys) {
$query->select('owner_userid')->from('user_departments')->where("id", "=", trim($keys['department'], ','));
});
});
$prefix = \DB::getTablePrefix();
$builder->selectRaw("if(EXISTS(select id from {$prefix}user_departments where owner_userid = userid and id={$keys['department']}),1,0) as is_principal");
$builder->orderBy("is_principal","desc");
}
}
if ($getCheckinMac && isset($keys['checkin_mac'])) {
@ -731,11 +741,14 @@ class UsersController extends AbstractController
$builder->whereNull('disable_at');
$builder->where('bot', 0);
}
$list = $builder->orderByDesc('userid')->paginate(Base::getPaginate(50, 20));
$builder = $keys['department'] == '0' ? $builder->orderByDesc('userid') : $builder;
$list = $builder->paginate(Base::getPaginate(50, 20));
//
if ($getCheckinMac) {
$list->transform(function (User $user) {
$list->transform(function (User $user) use ($getCheckinMac) {
if($getCheckinMac){
$user->checkin_macs = UserCheckinMac::select(['id', 'mac', 'remark'])->whereUserid($user->userid)->orderBy('id')->get();
}
return $user;
});
}

File diff suppressed because it is too large Load Diff

View File

@ -149,6 +149,15 @@ class User extends AbstractModel
return implode(', ', $array);
}
/**
* 判断是否为部门负责人
*/
public function isDepartmentOwner()
{
return UserDepartment::where('owner_userid', $this->userid)->exists();
}
/**
* 获取机器人所有者
* @return int|mixed
@ -605,6 +614,9 @@ class User extends AbstractModel
case 'anon-msg':
$update['nickname'] = '匿名消息';
break;
case 'approval-alert':
$update['nickname'] = '审批';
break;
case 'bot-manager':
$update['nickname'] = '机器人管理';
break;

View File

@ -0,0 +1,30 @@
<?php
namespace App\Models;
/**
* App\Models\WorkflowProcMsg
*
* @property int $id
* @property string|null $type 信息类型candidate-候选人、participant-参与人、notifier-抄送人)
* @property int|null $proc_inst_id 流程实例ID
* @property int|null $userid 会员ID
* @property int|null $msg_id 消息ID
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @method static \Illuminate\Database\Eloquent\Builder|WorkflowProcMsg newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|WorkflowProcMsg newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|WorkflowProcMsg query()
* @method static \Illuminate\Database\Eloquent\Builder|WorkflowProcMsg whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WorkflowProcMsg whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WorkflowProcMsg whereMsgId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WorkflowProcMsg whereProcInstId($value)
* @method static \Illuminate\Database\Eloquent\Builder|WorkflowProcMsg whereType($value)
* @method static \Illuminate\Database\Eloquent\Builder|WorkflowProcMsg whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|WorkflowProcMsg whereUserid($value)
* @mixin \Eloquent
*/
class WorkflowProcMsg extends AbstractModel
{
}

View File

@ -6,6 +6,12 @@
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
// 判断是否通过cmd命令执行的
if (function_exists('info')){
echo "Success \n";
return;
}
$path = dirname(__FILE__). '/';
$lists = scandir($path);
//

View File

@ -2985,4 +2985,43 @@ class Base
}
return false;
}
/**
* 多维数组字母转下划线格式
* @param $array
* @return array
*/
public static function arrayKeyToUnderline($array)
{
$newArray = [];
foreach ($array as $key => $value) {
//如果是数组,递归调用
if (is_array($value)) {
$value = self::arrayKeyToUnderline($value);
}
$newKey = strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $key));
$newArray[$newKey] = $value;
}
return $newArray;
}
/**
* 多维数组字母转驼峰格式
*
* @param [type] $array
* @return array
*/
public static function arrayKeyToCamel($array)
{
$newArray = [];
foreach ($array as $key => $value) {
//如果是数组,递归调用
if (is_array($value)) {
$value = self::arrayKeyToCamel($value);
}
$newKey = lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', $key))));
$newArray[$newKey] = $value;
}
return $newArray;
}
}

View File

@ -81,5 +81,7 @@
"sort-packages": true
},
"minimum-stability": "dev",
"prefer-stable": true
"prefer-stable": true,
"repositories": {
}
}

View File

@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateWorkflowProcMsgs extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (!Schema::hasTable('workflow_proc_msgs')) {
Schema::create('workflow_proc_msgs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('proc_inst_id')->nullable()->default(0)->comment('流程实例ID');
$table->bigInteger('userid')->nullable()->default(0)->comment('会员ID');
$table->bigInteger('msg_id')->nullable()->default(0)->comment('消息ID');
$table->timestamps();
});
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('workflow_proc_msgs', function (Blueprint $table) {
Schema::dropIfExists('workflow_proc_msgs');
});
}
}

View File

@ -49,6 +49,7 @@ services:
- drawio-webapp
- drawio-export
- minder
- workflow
restart: unless-stopped
redis:
@ -148,6 +149,24 @@ services:
ipv4_address: "${APP_IPPR}.10"
restart: unless-stopped
workflow:
container_name: "dootask-workflow-${APP_ID}"
image: "hitosea2020/go-workflow:latest"
environment:
TZ: "Asia/Shanghai"
MYSQL_HOST: "${DB_HOST}"
MYSQL_PORT: "${DB_PORT}"
MYSQL_DBNAME: "${DB_DATABASE}"
MYSQL_USERNAME: "${DB_USERNAME}"
MYSQL_PASSWORD: "${DB_PASSWORD}"
MYSQL_Prefix: "${DB_PREFIX}workflow_"
networks:
extnetwork:
ipv4_address: "${APP_IPPR}.11"
depends_on:
- mariadb
restart: unless-stopped
networks:
extnetwork:
name: "dootask-networks-${APP_ID}"

View File

@ -168,6 +168,21 @@ server {
proxy_set_header Server-Port $server_port;
proxy_pass http://minder/;
}
# 工作流
location /workflow/ {
proxy_pass http://workflow/;
}
location /workflow/api/ {
auth_request /workflowauth;
proxy_pass http://workflow/api/;
}
location /workflowauth {
internal;
proxy_set_header Content-Type "application/json";
proxy_set_header Content-Length $request_length;
proxy_pass http://service/api/workflow/verifyToken;
}
}
include /etc/nginx/conf.d/conf.d/*.conf;

View File

@ -446,3 +446,25 @@ Api接口文档
终端MAC与License不匹配
终端用户数超过License限制
终端License已过期
成功
查询失败
删除失败
启动失败
审批机器人不存在
创建成功
审批失败
已通过
已拒绝
撤回失败
已撤回
查询失败
参数错误
日期选择错误
日期范围限制最大35天
查询失败
开始时间 无效的时间格式
结束时间 无效的时间格式
开始时间不能大于结束时间
找不到符合条件的子节点

View File

@ -1136,3 +1136,92 @@ Markdown 格式发送
上传本地图片
浏览已上传图片
加载失败
待审批
审批中
已通过
已拒绝
已撤回
提交于
假期类型
开始时间
结束时间
时长
请假事由
审批记录
提交
已提交
审批
已等待
抄送
系统
自动抄送
等(*)人
结束
已结束
未结束
同意
拒绝
撤销
分钟
刚刚
分钟前
小时
小时前
分钟
请输入审批意见
你确定要撤销吗?
请选择部门!
请选择假期类型!
请选择开始时间!
请选择结束时间!
请输入事由!
年假
事假
病假
调休
产假
陪产假
婚假
丧假
哺乳假
外出
暂无数据
审批中心
待办
已办
抄送我
已发起
选择部门
请选择部门
假期类型
请选择假期类型
开始时间
请选择开始时间
结束时间
请选择结束时间
事由
全部审批
请假
加班申请
全部状态
发起时间
审批设置
是否发布
已发布
流程名称
自动通过,审批人与发起人为同一人
您当前未加入任何部门,不能发起!
请输入流程名称
将会清空流程数据,此操作不可恢复
添加申请
申请类型
请选择申请类型
请选择申请类型!
添加流程
全文评论
评论
内容
添加评论
请输入内容!

View File

@ -15739,5 +15739,962 @@
"de": "Geladen und geschlagen.",
"fr": "Échec au chargement",
"id": "Gagal memuat"
},
{
"key": "成功",
"zh": "",
"zh-CHT": "成功",
"en": "Success",
"ko": "성공",
"ja": "成功です",
"de": "Der erfolg",
"fr": "Le succès",
"id": "Berhasil"
},
{
"key": "查询失败",
"zh": "",
"zh-CHT": "查詢失敗",
"en": "Query failure",
"ko": "쿼리 실패",
"ja": "クエリ失敗です",
"de": "Abfrage abgebrochen",
"fr": "La requête a échoué",
"id": "Gagal penyelidikan"
},
{
"key": "启动失败",
"zh": "",
"zh-CHT": "啓動失敗",
"en": "Startup failure",
"ko": "시작 실패",
"ja": "起動失敗です",
"de": "Kein start.",
"fr": "Échec au démarrage",
"id": "Gagal menjalankan"
},
{
"key": "审批机器人不存在",
"zh": "",
"zh-CHT": "審批機器人不存在",
"en": "Approval bots don't exist",
"ko": "심사 로봇은 존재하지 않습니다",
"ja": "決裁ロボットは存在しません",
"de": "Die abschüsse gibt es nicht",
"fr": "Le robot dapprobation nexiste pas",
"id": "Persetujuan robot tidak ada"
},
{
"key": "审批失败",
"zh": "",
"zh-CHT": "審批失敗",
"en": "Approval failure",
"ko": "승인 실패",
"ja": "承認に失敗します",
"de": "Die genehmigung hat nicht bestanden.",
"fr": "Échec de lapprobation",
"id": "Persetujuan gagal"
},
{
"key": "已通过",
"zh": "",
"zh-CHT": "已通過",
"en": "Have passed",
"ko": "통과되다",
"ja": "通過しました",
"de": "Wurde angenommen.",
"fr": "A été adopté",
"id": "Telah berlalu"
},
{
"key": "已拒绝",
"zh": "",
"zh-CHT": "已拒絕",
"en": "Rejected",
"ko": "거부됨",
"ja": "お断りしました",
"de": "Abgelehnt.",
"fr": "A été refusé",
"id": "Telah ditolak"
},
{
"key": "撤回失败",
"zh": "",
"zh-CHT": "撤回失敗",
"en": "Retraction failure",
"ko": "실패를 철회하다",
"ja": "撤回失敗です",
"de": "Einwand.",
"fr": "Échec du retrait",
"id": "Penarikan gagal"
},
{
"key": "已撤回",
"zh": "",
"zh-CHT": "已撤回",
"en": "Withdrawn",
"ko": "이미 철회하다",
"ja": "撤回しました",
"de": "Einwand.",
"fr": "A été retiré",
"id": "Telah ditarik"
},
{
"key": "日期范围限制最大35天",
"zh": "",
"zh-CHT": "日期範圍限制最大35天",
"en": "The maximum date range is 35 days",
"ko": "날짜의 범위는 최대 35일이다",
"ja": "日時の制限は最大35日間です",
"de": "Die datumsgrenze ist auf höchstens 35 tage begrenzt",
"fr": "Plage de dates limite max 35 jours",
"id": "Batas tanggal 35 hari maksimum"
},
{
"key": "待审批",
"zh": "",
"zh-CHT": "待審批",
"en": "Pending approval",
"ko": "비준을 기다리다",
"ja": "審査待ちです",
"de": "Bitte öffnen.",
"fr": "En attente dapprobation",
"id": "Untuk persetujuan"
},
{
"key": "审批中",
"zh": "",
"zh-CHT": "審批中",
"en": "Under approval",
"ko": "심사 중",
"ja": "審査中です",
"de": "Ja, ich bestätige.",
"fr": "Approbation en cours",
"id": "Persetujuan diterima"
},
{
"key": "提交于",
"zh": "",
"zh-CHT": "提交於",
"en": "Submit to",
"ko": "다음으로 보내기",
"ja": "提出します",
"de": "Eingereicht in",
"fr": "Soumis à",
"id": "Diserahkan pada"
},
{
"key": "假期类型",
"zh": "",
"zh-CHT": "假期類型",
"en": "Type of vacation",
"ko": "휴가기간 유형",
"ja": "休暇のタイプです",
"de": "Typ urlaub?",
"fr": "Types de vacances",
"id": "Jenis liburan"
},
{
"key": "开始时间",
"zh": "",
"zh-CHT": "開始時間",
"en": "Start time",
"ko": "시작 시간",
"ja": "開始時間です",
"de": "Zeit zu starten.",
"fr": "Heure de début",
"id": "Waktu mulai"
},
{
"key": "结束时间",
"zh": "",
"zh-CHT": "結束時間",
"en": "End time",
"ko": "종료 시간",
"ja": "終了時間です",
"de": "Die zeit ist um.",
"fr": "Temps de fin",
"id": "Waktu untuk mengakhiri"
},
{
"key": "时长",
"zh": "",
"zh-CHT": "時長",
"en": "Duration",
"ko": "시간",
"ja": "時間の長さです",
"de": "Zeithalter.",
"fr": "La durée",
"id": "Terbatas,"
},
{
"key": "请假事由",
"zh": "",
"zh-CHT": "請假事由",
"en": "Reasons for leave",
"ko": "휴가 신청서",
"ja": "お休み申しあげます",
"de": "Haben sie urlaub?",
"fr": "Motif du congé",
"id": "Cuti terus"
},
{
"key": "审批记录",
"zh": "",
"zh-CHT": "審批記錄",
"en": "Approval record",
"ko": "심사 비준 기록",
"ja": "承認記録です",
"de": "Alle gespräche.",
"fr": "Enregistrement des approbations",
"id": "Catatan persetujuan"
},
{
"key": "已提交",
"zh": "",
"zh-CHT": "已提交",
"en": "Submitted",
"ko": "제출됨",
"ja": "提出しました",
"de": "Antrag eingereicht",
"fr": "A été soumis",
"id": "Telah diajukan"
},
{
"key": "审批",
"zh": "",
"zh-CHT": "審批",
"en": "Examine and approve",
"ko": "심사 비준",
"ja": "承認します",
"de": "Liste?",
"fr": "La réception",
"id": "Persetujuan"
},
{
"key": "已等待",
"zh": "",
"zh-CHT": "已等待",
"en": "Have been waiting",
"ko": "기다림",
"ja": "お待ちしております",
"de": "Ich warte",
"fr": "Déjà en attente",
"id": "Telah menunggu"
},
{
"key": "抄送",
"zh": "",
"zh-CHT": "抄送",
"en": "Copy",
"ko": "사본",
"ja": "Ccです",
"de": "Abschreiben",
"fr": "Cc",
"id": "Cc by-nc-sa 2."
},
{
"key": "自动抄送",
"zh": "",
"zh-CHT": "自動抄送",
"en": "Automatic cc",
"ko": "자동으로 참조",
"ja": "オートccです",
"de": "Handschrift folgt.",
"fr": "Automatique avec cc",
"id": "Salin otomatis"
},
{
"key": "等(*)人",
"zh": "",
"zh-CHT": "等(*)人",
"en": "Wait for (*) people",
"ko": "등 (*)인",
"ja": "(*)人です。",
"de": "Guy guy guy",
"fr": "Etc. (*) personne",
"id": "DLL (*) orang"
},
{
"key": "结束",
"zh": "",
"zh-CHT": "結束",
"en": "End",
"ko": "끝",
"ja": "終わります",
"de": "Und position halten!",
"fr": "La fin de la",
"id": "Berakhir"
},
{
"key": "已结束",
"zh": "",
"zh-CHT": "已結束",
"en": "Have ended",
"ko": "끝났음",
"ja": "終わりました",
"de": "Es ist vorbei",
"fr": "A été terminé",
"id": "Sudah berakhir"
},
{
"key": "未结束",
"zh": "",
"zh-CHT": "未結束",
"en": "Unfinished",
"ko": "미완성",
"ja": "終わりません",
"de": "Es ist noch nicht zu ende.",
"fr": "Sans fin",
"id": "Belum berakhir"
},
{
"key": "拒绝",
"zh": "",
"zh-CHT": "拒絕",
"en": "Refuse",
"ko": "거부",
"ja": "お断りします",
"de": "Wie? - nein!",
"fr": "Le refus",
"id": "Menolak"
},
{
"key": "刚刚",
"zh": "",
"zh-CHT": "剛剛",
"en": "Just now",
"ko": "방금",
"ja": "さっきです",
"de": "Eben erst?",
"fr": "Vient",
"id": "Baru saja"
},
{
"key": "分钟前",
"zh": "",
"zh-CHT": "分鐘前",
"en": "A minute ago",
"ko": "분 전",
"ja": "分前です",
"de": "Vor einer minute.",
"fr": "Quelques minutes avant",
"id": "Menit yang lalu"
},
{
"key": "小时前",
"zh": "",
"zh-CHT": "小時前",
"en": "Hour ago",
"ko": "시간 전",
"ja": "少し前です",
"de": "Vor einer stunde.",
"fr": "Heures avant",
"id": "Jam yang lalu"
},
{
"key": "请输入审批意见",
"zh": "",
"zh-CHT": "請輸入審批意見",
"en": "Please enter approval comments",
"ko": "심사 의견을 입력해 주세요",
"ja": "決裁意見の入力をお願いします。",
"de": "Bitte geben sie ein gutachten zur genehmigung ein",
"fr": "Veuillez entrer les commentaires dapprobation",
"id": "Mohon masukkan pendapat"
},
{
"key": "你确定要撤销吗?",
"zh": "",
"zh-CHT": "你確定要撤銷嗎?",
"en": "Are you sure you want to undo this?",
"ko": "취소하는 것이 확실합니까?",
"ja": "撤回するのは確実ですか?",
"de": "Soll ich's wirklich abblasen?",
"fr": "Êtes-vous sûr de vouloir annuler?",
"id": "Kau yakin ingin membatalkannya?"
},
{
"key": "请选择部门!",
"zh": "",
"zh-CHT": "請選擇部門!",
"en": "Please select a department!",
"ko": "부문을 선택해주세요!",
"ja": "部門をお願いします!",
"de": "Bitte wählen sie die abtei!",
"fr": "Veuillez sélectionner un département!",
"id": "Silahkan pilih bagian!"
},
{
"key": "请选择假期类型!",
"zh": "",
"zh-CHT": "請選擇假期類型!",
"en": "Please select the vacation type!",
"ko": "휴가 타입을 선택하세요!",
"ja": "休日タイプをお願いします!",
"de": "Bitte wählen sie die urlaubsorte!",
"fr": "Veuillez choisir le type de vacances!",
"id": "Silahkan pilih tipe liburan!"
},
{
"key": "请选择开始时间!",
"zh": "",
"zh-CHT": "請選擇開始時間!",
"en": "Please select a start time!",
"ko": "시작 시간을 선택하세요!",
"ja": "開始時間をお願いします!",
"de": "Bitte wählen sie die start-zeit!",
"fr": "Veuillez choisir une heure de départ!",
"id": "Silahkan pilih waktu untuk memulai!"
},
{
"key": "请选择结束时间!",
"zh": "",
"zh-CHT": "請選擇結束時間!",
"en": "Please select the end time!",
"ko": "마감 시간을 선택하세요!",
"ja": "終了時間をお願いします!",
"de": "Bitte wählen sie die endzeit!",
"fr": "Veuillez sélectionner une heure de fin!",
"id": "Silahkan pilih waktu untuk mengakhiri!"
},
{
"key": "请输入事由!",
"zh": "",
"zh-CHT": "請輸入事由!",
"en": "Please enter the reason!",
"ko": "사유를 입력해주세요!",
"ja": "用件を入力お願いします!",
"de": "Geben sie den eintrag ein!",
"fr": "Veuillez entrer un motif!",
"id": "Tolong masukkan atensinya!"
},
{
"key": "年假",
"zh": "",
"zh-CHT": "年假",
"en": "Annual leave",
"ko": "연가",
"ja": "年休です",
"de": "Urlaub.",
"fr": "Congé annuel",
"id": "Liburan."
},
{
"key": "事假",
"zh": "",
"zh-CHT": "事假",
"en": "Personal leave",
"ko": "사적 휴가",
"ja": "用の休暇です",
"de": "Feierabend.",
"fr": "Congé de maladie",
"id": "ShiJia"
},
{
"key": "病假",
"zh": "",
"zh-CHT": "病假",
"en": "Sick leave",
"ko": "병가",
"ja": "病気休暇です",
"de": "Krank geschrieben.",
"fr": "Un congé de maladie",
"id": "Lelah dan sakit."
},
{
"key": "调休",
"zh": "",
"zh-CHT": "調休",
"en": "Take working days off",
"ko": "휴가 날짜",
"ja": "振替休暇です",
"de": "Mobilisierung.",
"fr": "Congé",
"id": "DiaoXiu"
},
{
"key": "产假",
"zh": "",
"zh-CHT": "產假",
"en": "Maternity leave",
"ko": "출산 휴가",
"ja": "産休です",
"de": "Mutterschaftsurlaub.",
"fr": "Le congé de maternité",
"id": "Cuti hamil."
},
{
"key": "陪产假",
"zh": "",
"zh-CHT": "陪產假",
"en": "Paternity leave",
"ko": "육아 휴가",
"ja": "産休です",
"de": "Der vaterschaftsurlaub.",
"fr": "Congé de paternité",
"id": "Cuti bapa"
},
{
"key": "婚假",
"zh": "",
"zh-CHT": "婚假",
"en": "Wedding leave",
"ko": "결혼 휴가",
"ja": "結婚休暇です",
"de": "Richtig? - richtig.",
"fr": "Mariage",
"id": "HunJia"
},
{
"key": "丧假",
"zh": "",
"zh-CHT": "喪假",
"en": "Bereavement leave",
"ko": "복상 휴가",
"ja": "忌引休暇です",
"de": "Ich hatte verlust.",
"fr": "Congé de",
"id": "SangJia"
},
{
"key": "哺乳假",
"zh": "",
"zh-CHT": "哺乳假",
"en": "Lactation leave",
"ko": "수유휴가",
"ja": "授乳休暇です",
"de": "Urlaub machen.",
"fr": "Congé dallaitement",
"id": "Cuti menyusui"
},
{
"key": "暂无数据",
"zh": "",
"zh-CHT": "暫無數據",
"en": "No data yet",
"ko": "불충분한 증거",
"ja": "仮無数の根拠です",
"de": "Eine vermutung nimmt man Von zeit zu zeit.",
"fr": "Données non disponibles",
"id": "Sudah tak terhitung jumlahnya"
},
{
"key": "审批中心",
"zh": "",
"zh-CHT": "審批中心",
"en": "Approval center",
"ko": "심사허가센터",
"ja": "審査センターです",
"de": "Internationales überprüfungszentrum",
"fr": "Centre dagrément",
"id": "Pusat persetujuan"
},
{
"key": "已办",
"zh": "",
"zh-CHT": "已辦",
"en": "Done",
"ko": "이미 처리",
"ja": "やりました",
"de": "Erfolgreich.",
"fr": "Ont",
"id": "Wanita mereka"
},
{
"key": "抄送我",
"zh": "",
"zh-CHT": "抄送我",
"en": "Cc me",
"ko": "사본을 나에게 송달하다",
"ja": "Ccで送ります",
"de": "Abschreiben.",
"fr": "Cc pour moi",
"id": "Salin aku"
},
{
"key": "已发起",
"zh": "",
"zh-CHT": "已發起",
"en": "Initiated",
"ko": "이미 시작되다",
"ja": "発議しました",
"de": "Ach, spinnst du?",
"fr": "A été initié",
"id": "Telah dimulai"
},
{
"key": "选择部门",
"zh": "",
"zh-CHT": "選擇部門",
"en": "Select department",
"ko": "부문을 선정하다",
"ja": "部門を選びます。",
"de": "Bezirk gewählt.",
"fr": "Sélectionnez un département",
"id": "Pilih departemen"
},
{
"key": "请选择部门",
"zh": "",
"zh-CHT": "請選擇部門",
"en": "Please select department",
"ko": "부문을 선택하세요",
"ja": "部門の選択をお願いします。",
"de": "Wählt eure abteilung aus.",
"fr": "Veuillez sélectionner un département",
"id": "Silahkan pilih jurusan"
},
{
"key": "请选择假期类型",
"zh": "",
"zh-CHT": "請選擇假期類型",
"en": "Please select a vacation type",
"ko": "휴가철을 선택하세요",
"ja": "休日のタイプをお願いします。",
"de": "Bitte wählen sie einen urlaubstyp",
"fr": "Veuillez sélectionner le type de vacances",
"id": "Silahkan pilih tipe liburan"
},
{
"key": "请选择开始时间",
"zh": "",
"zh-CHT": "請選擇開始時間",
"en": "Please select a start time",
"ko": "시작 시간을 선택하세요",
"ja": "開始時間をお願いします",
"de": "Bitte wählen sie einen start aus",
"fr": "Veuillez sélectionner une heure de départ",
"id": "Silahkan pilih waktu untuk memulai"
},
{
"key": "请选择结束时间",
"zh": "",
"zh-CHT": "請選擇結束時間",
"en": "Please select an end time",
"ko": "마감시간을 선택하세요",
"ja": "終了時間をお願いします。",
"de": "Bitte wählen sie den endzeitpunkt aus",
"fr": "Veuillez sélectionner une heure de fin",
"id": "Silahkan pilih waktu untuk mengakhiri"
},
{
"key": "事由",
"zh": "",
"zh-CHT": "事由",
"en": "Cause",
"ko": "사유",
"ja": "事由です",
"de": "Es war ein unfall",
"fr": "Objet",
"id": "Akan memberikan berita"
},
{
"key": "全部审批",
"zh": "",
"zh-CHT": "全部審批",
"en": "All approval",
"ko": "전체 승인",
"ja": "すべて承認します",
"de": "Alle gespräche.",
"fr": "Toutes les approbations",
"id": "Semua persetujuan"
},
{
"key": "请假",
"zh": "",
"zh-CHT": "請假",
"en": "Ask for leave",
"ko": "휴가를 얻어",
"ja": "休暇を取ります",
"de": "Urlaub nehmen.",
"fr": "Congés",
"id": "Cuti"
},
{
"key": "加班申请",
"zh": "",
"zh-CHT": "加班申請",
"en": "Overtime",
"ko": "잔업 신청",
"ja": "残業申請です",
"de": "Antrag für überstunden",
"fr": "Demande dheures supplémentaires",
"id": "Aplikasi lembur"
},
{
"key": "全部状态",
"zh": "",
"zh-CHT": "全部狀態",
"en": "Total state",
"ko": "모든 상태",
"ja": "全ての状態です",
"de": "Reisedauer studiert.",
"fr": "État de tous",
"id": "Semua status"
},
{
"key": "发起时间",
"zh": "",
"zh-CHT": "發起時間",
"en": "Initiation time",
"ko": "발기 시간",
"ja": "発起時期です",
"de": "Promoter zeit!",
"fr": "Heure de lancement",
"id": "Waktu diprakarsai"
},
{
"key": "开始时间 无效的时间格式",
"zh": "",
"zh-CHT": "開始時間 無效的時間格式",
"en": "Start Time Invalid time format",
"ko": "시작 시간의 시간 형식이 잘못되었습니다",
"ja": "開始時間無効の時間フォーマットです",
"de": "Der zeitbegriff beginnt nicht gültig",
"fr": "Heure de début format de temps invalide",
"id": "Mulailah format waktu yang tidak valid"
},
{
"key": "结束时间 无效的时间格式",
"zh": "",
"zh-CHT": "結束時間 無效的時間格式",
"en": "End Time Indicates the invalid time format",
"ko": "종료 시간 형식이 잘못되었습니다",
"ja": "終了時間無効のタイムフォーマットです",
"de": "Der zeitbegriff ist nicht aktuell genug",
"fr": "Heure de fin format de temps invalide",
"id": "Format waktu saat berakhirnya waktu yang tidak valid"
},
{
"key": "开始时间不能大于结束时间",
"zh": "",
"zh-CHT": "開始時間不能大於結束時間",
"en": "The start time cannot be later than the end time",
"ko": "시작 시간이 종료 시간보다 많아서는 안 된다",
"ja": "開始時間が終了時間を超えてはいけません",
"de": "Der anfang darf nicht größer sein als das ende",
"fr": "Lheure de début ne peut pas être plus grande que lheure de fin",
"id": "Waktu untuk memulai tidak lebih dari waktu untuk mengakhiri"
},
{
"key": "审批设置",
"zh": "",
"zh-CHT": "審批設置",
"en": "Approval setting",
"ko": "설정 승인",
"ja": "承認設置です。",
"de": "Zulassungsstelle",
"fr": "Approbation et configuration",
"id": "Pengaturan persetujuan"
},
{
"key": "是否发布",
"zh": "",
"zh-CHT": "是否發佈",
"en": "Whether to publish",
"ko": "게시 여부",
"ja": "発表するかどうかです",
"de": "Veröffentlichen sie es.",
"fr": "Oui non publié",
"id": "Rilis atau tidak"
},
{
"key": "流程名称",
"zh": "",
"zh-CHT": "流程名稱",
"en": "Process name",
"ko": "스트림 이름",
"ja": "プロセス名です",
"de": "Name des laufes?",
"fr": "Nom du processus",
"id": "Nama proses"
},
{
"key": "自动通过,审批人与发起人为同一人",
"zh": "",
"zh-CHT": "自動通過,審批人與發起人爲同一人",
"en": "Automatically passed, the approver and the initiator are the same person",
"ko": "자동통과는 심사인과 발기인이 동일인이 된다",
"ja": "自動的に承認され、決裁者は発起人と同じ人です",
"de": "Automatisch durchgeführt, und die person, die damit beauftragt wurde, ist die person, die damit beauftragt wurde",
"fr": "Passage automatique, approbation et initiateur sont la même personne",
"id": "Secara otomatis lewat, auditor dan si pendiri adalah orang yang sama"
},
{
"key": "您当前未加入任何部门,不能发起!",
"zh": "",
"zh-CHT": "您當前未加入任何部門,不能發起!",
"en": "You have not joined any department at present, cannot initiate!",
"ko": "현재 어떤 부서에 가입되어 있지 않습니다. 시작할 수 없습니다!",
"ja": "現在、どの部門にも所属していないので、発議することはできません!",
"de": "Sie sind noch nicht aktiv in einer abteilung!",
"fr": "Vous nêtes actuellement affilié à aucun département et ne pouvez pas initier!",
"id": "Anda saat ini tidak bergabung dengan divisi manapun, tidak bisa memulai!"
},
{
"key": "找不到符合条件的子节点",
"zh": "",
"zh-CHT": "找不到符合條件的子節點",
"en": "No suitable child node could be found",
"ko": "일치하는 자식 노드를 찾을 수 없습니다",
"ja": "該当する子ノードが見つかりません",
"de": "Es kann keine richtige subgruppe gefunden werden",
"fr": "Aucun enfant éligible na été trouvé",
"id": "Tidak dapat menemukan subnode yang sesuai"
},
{
"key": "外出",
"zh": "",
"zh-CHT": "外出",
"en": "Go out",
"ko": "외출",
"ja": "外出します",
"de": "Justine: aus.",
"fr": "À lextérieur",
"id": "Pergi ke luar"
},
{
"key": "已发布",
"zh": "",
"zh-CHT": "已發佈",
"en": "Published",
"ko": "발표됨",
"ja": "発表されました",
"de": "Bereit zu",
"fr": "Publié dans",
"id": "Telah diterbitkan"
},
{
"key": "请输入流程名称",
"zh": "",
"zh-CHT": "請輸入流程名稱",
"en": "Please enter a process name",
"ko": "스트림명을 입력하십시오",
"ja": "プロセス名を入力願います。",
"de": "Geben sie einen namen für ihren vorgang ein",
"fr": "Veuillez entrer le nom du processus",
"id": "Nama proses, silakan"
},
{
"key": "将会清空流程数据,此操作不可恢复",
"zh": "",
"zh-CHT": "將會清空流程數據,此操作不可恢復",
"en": "The process data will be cleared. This operation cannot be restored",
"ko": "스트림 데이터를 비우게 됩니다. 다시 시작할 수 없습니다",
"ja": "プロセスデータをクリアします。この操作は復元できません。",
"de": "Die prozessdaten werden dann gelöscht und die vorgang kann nicht wiederhergestellt werden",
"fr": "Vider les données du processus. Cette action nest pas récupérable",
"id": "Operasi ini tidak dapat dipulihkan"
},
{
"key": "添加申请",
"zh": "",
"zh-CHT": "添加申請",
"en": "Add application",
"ko": "신청 추가",
"ja": "申請を追加します。",
"de": "Antrag hinzufügen.",
"fr": "Ajouter une application",
"id": "Tambah aplikasi"
},
{
"key": "请选择申请类型!",
"zh": "",
"zh-CHT": "請選擇申請類型!",
"en": "Please select the application type!",
"ko": "신청 종류를 선택하세요!",
"ja": "申し込みタイプをお願いします!",
"de": "Bitte wählen sie den bewerbungstyp!",
"fr": "Veuillez sélectionner le type de demande!",
"id": "Silahkan pilih tipe aplikasi!"
},
{
"key": "请选择申请类型",
"zh": "",
"zh-CHT": "請選擇申請類型",
"en": "Please select an application type",
"ko": "신청 종류를 선택하세요",
"ja": "申し込みの種類を選択します。",
"de": "Bitte wählen sie den bewerbungstyp aus",
"fr": "Veuillez sélectionner le type de demande",
"id": "Silahkan pilih tipe aplikasi"
},
{
"key": "申请类型",
"zh": "",
"zh-CHT": "申請類型",
"en": "Type of application",
"ko": "신청 유형",
"ja": "申し込みの種類です",
"de": "Art des antrags:",
"fr": "Type de demande",
"id": "Tipe aplikasi"
},
{
"key": "添加流程",
"zh": "",
"zh-CHT": "添加流程",
"en": "Add process",
"ko": "프로세스 추가",
"ja": "プロセスを追加します",
"de": "Schleifen lassen",
"fr": "Ajouter un processus",
"id": "Tambahkan alur"
},
{
"key": "全文评论",
"zh": "",
"zh-CHT": "全文評論",
"en": "Full text review",
"ko": "전문 평론",
"ja": "全文コメントです。",
"de": "Whistler whistler?",
"fr": "Commentaires complets",
"id": "Ulasan lengkap"
},
{
"key": "评论",
"zh": "",
"zh-CHT": "評論",
"en": "Comment",
"ko": "논평",
"ja": "レビューです",
"de": "Kommentar.",
"fr": "Commentaires",
"id": "Komentar"
},
{
"key": "内容",
"zh": "",
"zh-CHT": "內容",
"en": "Content",
"ko": "내용",
"ja": "中身です",
"de": "Inhalt.",
"fr": "Le contenu",
"id": "Isi"
},
{
"key": "添加评论",
"zh": "",
"zh-CHT": "添加評論",
"en": "Add a comment",
"ko": "코멘트 더하기",
"ja": "コメントを書きます。",
"de": "Geben sie mir ein zitat.",
"fr": "Ajouter un commentaire",
"id": "Tambahkan komentar"
},
{
"key": "请输入内容!",
"zh": "",
"zh-CHT": "請輸入內容!",
"en": "Please enter the content!",
"ko": "내용을 입력하십시오!",
"ja": "内容の入力をお願いします!",
"de": "Bitte geben sie den inhalt ein!",
"fr": "Veuillez entrer le contenu!",
"id": "Silahkan isi!"
}
]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""]
["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
if(typeof window.LANGUAGE_DATA==="undefined")window.LANGUAGE_DATA={};window.LANGUAGE_DATA["zh"]=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""]
if(typeof window.LANGUAGE_DATA==="undefined")window.LANGUAGE_DATA={};window.LANGUAGE_DATA["zh"]=["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""]

View File

@ -84,6 +84,7 @@ export default {
],
[
{icon: '&#xe7da;', name: 'workReport', label: '工作报告'},
{icon: '&#xe7b9;', name: 'review', label: '审批中心'},
]
],

View File

@ -881,6 +881,7 @@
if (typeof config === "string") config = {title:config};
let inputId = "modalInput_" + $A.randomString(6);
let inputProps = {
type: config.type || "text",
value: config.value,
placeholder: $A.L(config.placeholder),
elementId: inputId,

View File

@ -11,7 +11,7 @@
<UserAvatar :userid="userId" :size="36" tooltipDisabled/>
</div>
<span>{{userInfo.nickname}}</span>
<Badge v-if="reportUnreadNumber > 0" class="manage-box-top-report" :overflow-count="999" :count="reportUnreadNumber"/>
<Badge v-if="(reportUnreadNumber + backlogUnreadNumber) > 0" class="manage-box-top-report" :overflow-count="999" :count="reportUnreadNumber + backlogUnreadNumber"/>
<Badge v-else-if="!!clientNewVersion" class="manage-box-top-report" dot/>
<div class="manage-box-arrow">
<Icon type="ios-arrow-up" />
@ -72,6 +72,7 @@
<DropdownItem name="exportTask">{{$L('导出任务统计')}}</DropdownItem>
<DropdownItem name="exportOverdueTask">{{$L('导出超期任务')}}</DropdownItem>
<DropdownItem name="exportCheckin">{{$L('导出签到数据')}}</DropdownItem>
<DropdownItem name="exportWorkflow">{{$L('导出审批数据')}}</DropdownItem>
</DropdownMenu>
</Dropdown>
<!-- 其他菜单 -->
@ -90,6 +91,10 @@
v-else-if="item.path === 'workReport' && reportUnreadNumber > 0"
class="manage-menu-report-badge"
:count="reportUnreadNumber"/>
<Badge
v-else-if="item.path === 'review' && backlogUnreadNumber > 0"
class="manage-menu-report-badge"
:count="backlogUnreadNumber"/>
</div>
</DropdownItem>
</template>
@ -243,6 +248,9 @@
<!--导出签到数据-->
<CheckinExport v-model="exportCheckinShow"/>
<!--导出审批数据-->
<WorkflowExport v-model="exportWorkflowShow"/>
<!--任务详情-->
<TaskModal ref="taskModal"/>
@ -310,6 +318,7 @@ import DialogModal from "./manage/components/DialogModal";
import TaskModal from "./manage/components/TaskModal";
import CheckinExport from "./manage/components/CheckinExport";
import TaskExport from "./manage/components/TaskExport";
import WorkflowExport from "./manage/components/WorkflowExport";
import notificationKoro from "notification-koro1";
import {Store} from "le5le-store";
@ -317,6 +326,7 @@ export default {
components: {
TaskExport,
CheckinExport,
WorkflowExport,
TaskModal,
DialogModal,
MeetingManager,
@ -354,6 +364,8 @@ export default {
exportTaskShow: false,
exportCheckinShow: false,
exportWorkflowShow: false,
dialogMsgSubscribe: null,
@ -396,6 +408,7 @@ export default {
this.$store.dispatch("getUserInfo").catch(_ => {})
this.$store.dispatch("getTaskPriority").catch(_ => {})
this.$store.dispatch("getReportUnread", 0)
this.$store.dispatch("getBacklogUnread", 0)
//
this.$store.dispatch("needHome").then(_ => {
this.needStartHome = true
@ -441,6 +454,7 @@ export default {
'dialogIns',
'reportUnreadNumber',
'backlogUnreadNumber',
]),
...mapGetters(['dashboardTask']),
@ -546,11 +560,12 @@ export default {
{path: 'archivedProject', name: '已归档的项目'},
{path: 'team', name: '团队管理', divided: true},
{path: 'review', name: '审批中心'},
])
} else {
array.push(...[
{path: 'personal', name: '个人设置', divided: true},
{path: 'review', name: '审批中心'},
{path: 'version', name: '更新版本', divided: true, visible: !!this.clientNewVersion},
{path: 'workReport', name: '工作报告', divided: true},
@ -685,6 +700,11 @@ export default {
this.$store.dispatch("getReportUnread", 1000)
}
break;
case 'workflow':
if (action == 'backlog') {
this.$store.dispatch("getBacklogUnread", 1000)
}
break;
}
},
deep: true,
@ -732,6 +752,9 @@ export default {
case 'exportCheckin':
this.exportCheckinShow = true;
return;
case 'exportWorkflow':
this.exportWorkflowShow = true;
return;
case 'workReport':
if (this.reportUnreadNumber > 0) {
this.reportTabs = "receive";
@ -751,6 +774,11 @@ export default {
this.goForward('index');
}
return;
case 'review':
if (this.menu.findIndex((m) => m.path == path) > -1) {
this.goForward({name: 'manage-review'});
}
return;
case 'logout':
$A.modalConfirm({
title: '退出登录',

View File

@ -497,6 +497,11 @@
</div>
</div>
</DrawerOverlay>
<!--审批详情-->
<DrawerOverlay v-model="approveDetailsShow" placement="right" :size="600">
<ReviewDetails v-if="approveDetailsShow" :data="approveDetails" style="height: 100%;border-radius: 10px;"></ReviewDetails>
</DrawerOverlay>
</div>
</template>
@ -516,6 +521,8 @@ import DialogSelect from "./DialogSelect";
import ImgUpload from "../../../components/ImgUpload.vue";
import {choiceEmojiOne} from "./ChatInput/one";
import ReviewDetails from "../../../pages/manage/review/details.vue";
export default {
name: "DialogWrapper",
components: {
@ -528,7 +535,8 @@ export default {
DialogGroupInfo,
DrawerOverlay,
UserInput,
DialogUpload
DialogUpload,
ReviewDetails
},
props: {
@ -639,6 +647,9 @@ export default {
scrollTmp: 0,
positionLoad: 0,
approveDetails:{id: 0},
approveDetailsShow: false
}
},
@ -2374,6 +2385,22 @@ export default {
if (this.operateVisible) {
return
}
//
let domAudits = $(target).parents(".open-review-details")
if( domAudits.length > 0 ){
let dataId = domAudits[0].getAttribute("data-id")
if( window.innerWidth < 426 ){
this.goForward({name: 'manage-review-details', query: { id: domAudits[0].getAttribute("data-id") } });
}else{
this.approveDetailsShow = true;
this.$nextTick(()=>{
this.approveDetails = {id:dataId};
})
}
return;
}
switch (target.nodeName) {
case "IMG":
if (target.classList.contains('browse')) {
@ -2390,6 +2417,7 @@ export default {
this.$store.dispatch("openTask", $A.runNum(target.getAttribute("data-id")));
}
break;
}
},

View File

@ -340,7 +340,7 @@ export default {
minWidth: 160,
render: (h, {row}) => {
const arr = [h('AutoTip', row.email)];
const {email_verity, identity, disable_at} = row;
const {email_verity, identity, disable_at, is_principal} = row;
if (email_verity) {
arr.push(h('Icon', {
props: {
@ -348,6 +348,13 @@ export default {
}
}))
}
if (is_principal) {
arr.push(h('Tag', {
props: {
color: 'blue'
}
}, this.$L('负责人')))
}
if (identity.includes("ldap")) {
arr.push(h('Tag', {
props: {

View File

@ -0,0 +1,133 @@
<template>
<Modal
v-model="show"
:title="$L('导出审批数据')"
:mask-closable="false">
<Form ref="exportTask" :model="formData" label-width="auto" @submit.native.prevent>
<FormItem :label="$L('审批类型')">
<Select v-model="formData.proc_def_name" @on-open-change="getProcName">
<Option v-for="(item, key) in procList" :value="item.name" :key="key" >{{ item.name }}</Option>
</Select>
</FormItem>
<FormItem :label="$L('时间范围')">
<DatePicker
v-model="formData.date"
type="daterange"
format="yyyy/MM/dd"
style="width:100%"
:placeholder="$L('请选择时间')"/>
<div class="form-tip checkin-export-quick-select">
<span>{{$L('快捷选择')}}:</span>
<em @click="formData.date=dateShortcuts('prev')">{{$L('上个月')}}</em>
<em @click="formData.date=dateShortcuts('this')">{{$L('这个月')}}</em>
</div>
</FormItem>
<FormItem prop="type" :label="$L('导出类型')">
<RadioGroup v-model="formData.is_finished">
<Radio label="0">{{$L('未完成')}}</Radio>
<Radio label="1">{{$L('已完成')}}</Radio>
</RadioGroup>
</FormItem>
</Form>
<div slot="footer" class="adaption">
<Button type="default" @click="show=false">{{$L('取消')}}</Button>
<Button type="primary" :loading="loadIng > 0" @click="onExport">{{$L('导出')}}</Button>
</div>
</Modal>
</template>
<style lang="scss">
.checkin-export-quick-select {
> span {
margin-right: 4px;
}
> em {
margin-right: 4px;
cursor: pointer;
color: #2b85e4;
font-style: normal;
&:hover {
text-decoration: underline;
}
}
}
</style>
<script>
import UserInput from "../../../components/UserInput";
export default {
name: "WorkflowExport",
components: {UserInput},
props: {
value: {
type: Boolean,
default: false
},
},
data() {
return {
show: this.value,
loadIng: 0,
formData: {
proc_def_name: '',
date: [],
is_finished:'1',
},
procList:[],
}
},
watch: {
value(v) {
this.show = v;
},
show(v) {
this.value !== v && this.$emit("input", v)
}
},
methods: {
dateShortcuts(act) {
if (act === 'prev') {
return [$A.getSpecifyDate('上个月'), $A.getSpecifyDate('上个月结束')];
} else if (act === 'this') {
return [$A.getSpecifyDate('本月'), $A.getSpecifyDate('本月结束')]
}
},
getProcName(){
this.loadIng++;
this.$store.dispatch("call", {
url: 'workflow/procdef/all',
method: 'post'
}).then(({data}) => {
this.procList = data['rows'];
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
},
onExport() {
if (this.loadIng > 0) {
return;
}
this.loadIng++;
this.$store.dispatch("call", {
url: 'workflow/export',
data: this.formData,
}).then(({data}) => {
this.show = false;
this.$store.dispatch('downUrl', {
url: data.url
});
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
}
}
}
</script>

View File

@ -0,0 +1,434 @@
<template>
<div class="review-details" :style="{'z-index':modalTransferIndex}">
<div class="review-details-box">
<h2 class="review-details-title">
<span>{{$L(datas.proc_def_name)}}</span>
<Tag v-if="datas.state == 0" color="cyan">{{$L('待审批')}}</Tag>
<Tag v-if="datas.state == 1" color="cyan">{{$L('审批中')}}</Tag>
<Tag v-if="datas.state == 2" color="green">{{$L('已通过')}}</Tag>
<Tag v-if="datas.state == 3" color="red">{{$L('已拒绝')}}</Tag>
<Tag v-if="datas.state == 4" color="red">{{$L('已撤回')}}</Tag>
</h2>
<h3 class="review-details-subtitle"><Avatar :src="datas.userimg" size="24"/><span>{{datas.start_user_name}}</span></h3>
<h3 class="review-details-subtitle"><span>{{$L('提交于')}} {{datas.start_time}}</span></h3>
<Divider/>
<div class="review-details-text" v-if="(datas.proc_def_name || '').indexOf('班') == -1">
<h4>{{$L('假期类型')}}</h4>
<p>{{$L(datas.var?.type)}}</p>
</div>
<div class="review-details-text">
<h4>{{$L('开始时间')}}</h4>
<p>{{datas.var?.start_time}}</p>
</div>
<div class="review-details-text">
<h4>{{$L('结束时间')}}</h4>
<p>{{datas.var?.end_time}}</p>
</div>
<div class="review-details-text">
<h4>{{ $L('时长') }}{{getTimeDifference(datas.var?.start_time,datas.var?.end_time)['unit']}}</h4>
<p>{{ datas.var?.start_time ? getTimeDifference(datas.var?.start_time,datas.var?.end_time)['time'] : 0 }}</p>
</div>
<div class="review-details-text">
<h4>{{$L('请假事由')}}</h4>
<p>{{datas.var?.description}}</p>
</div>
<div class="review-details-text" v-if="datas.var?.other">
<h4>{{$L('图片')}}</h4>
<div class="img-body">
<div v-for="(src,key) in (datas.var.other).split(',') " @click="onViewPicture(src)">
<ImgView :src="src" :key="key" class="img-view"/>
</div>
</div>
</div>
<Divider/>
<h3 class="review-details-subtitle">{{$L('审批记录')}}</h3>
<Timeline class="review-record-timeline">
<template v-for="(item,key) in datas.node_infos">
<!-- 提交 -->
<TimelineItem :key="key" v-if="item.type == 'starter'" color="green">
<p class="timeline-title">{{$L('提交')}}</p>
<div class="timeline-body">
<Avatar :src="data.userimg || datas.userimg" size="38"/>
<div class="review-process-left">
<p class="review-process-name">{{data.start_user_name || datas.start_user_name}}</p>
<p class="review-process-state">{{$L('已提交')}}</p>
</div>
<div class="review-process-right">
<p v-if="parseInt(getTimeAgo(item.claim_time)) < showTimeNum">{{ getTimeAgo(item.claim_time) }}</p>
<p>{{item.claim_time?.substr(0,16)}}</p>
</div>
</div>
</TimelineItem>
<!-- 审批 -->
<TimelineItem :key="key" v-if="item.type == 'approver' && item._show"
:color="item.identitylink ? (item.identitylink?.state > 1 ? '#f03f3f' :'green') : '#ccc'"
>
<p class="timeline-title">{{$L('审批')}}</p>
<div class="timeline-body">
<Avatar :src="(item.node_user_list && item.node_user_list[0]?.userimg) || item.userimg" size="38"/>
<div class="review-process-left">
<p class="review-process-name">{{item.approver}}</p>
<p class="review-process-state" style="color: #6d6d6d;" v-if="!item.identitylink">待审批</p>
<p class="review-process-state" v-if="item.identitylink">
<span v-if="item.identitylink.state==0" style="color:#496dff;">{{$L('审批中')}}</span>
<span v-if="item.identitylink.state==1" >{{$L('已通过')}}</span>
<span v-if="item.identitylink.state==2" style="color:#f03f3f;">{{$L('已拒绝')}}</span>
<span v-if="item.identitylink.state==3" style="color:#f03f3f;">{{$L('已撤回')}}</span>
</p>
</div>
<div class="review-process-right">
<p v-if="parseInt(getTimeAgo(item.claim_time)) < showTimeNum">
{{ item.identitylink?.state==0 ?
($L('已等待') + " " + getTimeAgo( datas.node_infos[key-1].claim_time,2)) :
(item.claim_time ? getTimeAgo(item.claim_time) : '')
}}
</p>
<p>{{item.claim_time?.substr(0,16)}}</p>
</div>
</div>
<p class="comment" v-if="item.identitylink?.comment"><span>{{ item.identitylink?.comment }}</span></p>
</TimelineItem>
<!-- 抄送 -->
<TimelineItem :key="key" :color="item.is_finished ? 'green' : '#ccc'" v-if="item.type == 'notifier' && item._show">
<p class="timeline-title">{{$L('抄送')}}</p>
<div class="timeline-body">
<Avatar :src="'/images/avatar/default_bot.png'" size="38"/>
<div class="review-process-left">
<p class="review-process-name">{{$L('系统')}}</p>
<p style="font-size: 12px;">{{$L('自动抄送')}}
<span style="color: #486fed;">
{{ item.node_user_list?.map(h=>h.name).join(',') }}
{{$L('等'+item.node_user_list?.length+'人')}}
</span>
</p>
</div>
</div>
</TimelineItem>
<!-- 结束 -->
<TimelineItem :key="key" :color="item.is_finished ? 'green' : '#ccc'" v-if="item.aprover_type == 'end'">
<p class="timeline-title">{{$L('结束')}}</p>
<div class="timeline-body">
<Avatar :src="'/images/avatar/default_bot.png'" size="38"/>
<div class="review-process-left">
<p class="review-process-name">{{$L('系统')}}</p>
<p style="font-size: 12px;"> {{ datas.is_finished ? $L('已结束') : $L('未结束') }}</p>
</div>
</div>
</TimelineItem>
</template>
</Timeline>
<template v-if="datas.global_comment">
<Divider/>
<h3 class="review-details-subtitle">{{$L('全文评论')}}</h3>
<div class="review-record-comment">
<List :split="false" :border="false">
<ListItem v-for="(item,key) in datas.global_comments" :key="key">
<div>
<div class="top">
<Avatar :src="item.userimg" size="38"/>
<div>
<p>{{item.nickname}}</p>
<p class="time">{{item.created_at}}</p>
</div>
<span>{{ getTimeAgo(item.created_at ,2) }}</span>
</div>
<div class="content">
{{ getContent(item.content) }}
</div>
<div class="content" style="display: flex; gap: 10px;">
<div v-for="(src,k) in getPictures(item.content)" :key="k" @click="onViewPicture(src)">
<ImgView :src="src" class="img-view"/>
</div>
</div>
</div>
</ListItem>
</List>
</div>
</template>
</div>
<div class="review-operation">
<div style="flex: 1;"></div>
<Button type="success" v-if="(datas.candidate || '').split(',').indexOf(userId + '') != -1" @click="approve(1)">{{$L('同意')}}</Button>
<Button type="error" v-if="(datas.candidate || '').split(',').indexOf(userId + '') != -1" @click="approve(2)">{{$L('拒绝')}}</Button>
<Button type="warning" v-if="isShowWarningBtn" @click="revocation">{{$L('撤销')}}</Button>
<Button @click="comment" type="success" ghost>+{{$L('添加评论')}}</Button>
</div>
<!--评论-->
<Modal v-model="commentShow" :title="$L('评论')" :mask-closable="false" class="page-review-initiate">
<Form ref="initiateRef" :model="commentData" :rules="commentRule" label-width="auto" @submit.native.prevent>
<FormItem prop="content" :label="$L('内容')">
<Input type="textarea" v-model="commentData.content"></Input>
</FormItem>
<FormItem prop="pictures" :label="$L('图片')">
<ImgUpload v-model="commentData.pictures" :num="3" :width="512" :height="512" :whcut="1"></ImgUpload>
</FormItem>
</Form>
<div slot="footer" class="adaption">
<Button type="default" @click="commentShow=false">{{$L('取消')}}</Button>
<Button type="primary" :loading="loadIng > 0" @click="confirmComment">{{$L('确认')}}</Button>
</div>
</Modal>
</div>
</template>
<script>
import ImgView from "../../../components/ImgView";
import ImgUpload from "../../../components/ImgUpload";
export default {
name: "details",
components:{ImgView,ImgUpload},
props: {
data: {
type: Object,
default() {
return {};
}
}
},
data() {
return {
modalTransferIndex:window.modalTransferIndex,
datas:{},
showTimeNum:24,
commentShow:false,
loadIng:0,
commentData: {
content:"",
pictures:[]
},
commentRule: {
content: { type: 'string',required: true, message: this.$L('请输入内容!'), trigger: 'change' },
}
}
},
watch: {
'$route' (to, from) {
if(to.name == 'manage-review-details'){
this.init()
}
},
data: {
handler(newValue,oldValue) {
if(newValue.id){
this.getInfo()
}
},
deep: true
},
},
computed: {
isShowWarningBtn(){
let is = (this.userId == this.datas.start_user_id);
(this.datas.node_infos || []).map(h=>{
if(h.type != 'starter' && h.is_finished == true && h.identitylink?.userid != this.userId) {
is = false;
}
})
return is;
},
},
mounted() {
this.init()
},
methods:{
init(){
this.modalTransferIndex = window.modalTransferIndex = window.modalTransferIndex + 1
if(this.$route.query.id){
this.data.id = this.$route.query.id;
this.getInfo()
}
},
//
getTimeAgo(time,type) {
const currentTime = new Date();
const timeDiff = (currentTime - new Date((time + '').replace(/-/g,"/"))) / 1000; // convert to seconds
if (timeDiff < 60) {
return type == 2 ? "0"+this.$L('分钟') : this.$L('刚刚');
} else if (timeDiff < 3600) {
const minutes = Math.floor(timeDiff / 60);
return type == 2 ? `${minutes}${this.$L('分钟')}` : `${minutes} ${this.$L('分钟前')}`;
} else if(timeDiff < 3600 * 24) {
const hours = Math.floor(timeDiff / 3600);
return type == 2 ? `${hours}${this.$L('小时')}` : `${hours} ${this.$L('小时前')}`;
} else {
const days = Math.floor(timeDiff / 3600 / 24);
return type == 2 ? `${days+1}${this.$L('天')}` : `${days+1} ${this.$L('天')}`;
}
},
//
getTimeDifference(startTime,endTime) {
const currentTime = new Date((endTime + '').replace(/-/g,"/"));
const timeDiff = (currentTime - new Date((startTime + '').replace(/-/g,"/"))) / 1000; // convert to seconds
if (timeDiff < 60) {
return {time:timeDiff,unit:this.$L('秒')};
} else if (timeDiff < 3600) {
const minutes = Math.floor(timeDiff / 60);
return {time:minutes,unit:this.$L('分钟')};
} else if(timeDiff < 3600 * 24) {
const hours = Math.floor(timeDiff / 3600);
return {time:hours,unit:this.$L('小时')};
} else {
const days = Math.floor(timeDiff / 3600 / 24);
return {time:days + 1,unit:this.$L('天')};
}
},
//
getInfo(){
this.datas = this.data
this.$store.dispatch("call", {
method: 'get',
url: 'workflow/process/detail',
data: {
id:this.data.id,
}
}).then(({data}) => {
var show = true;
data.node_infos = data.node_infos.map(item=>{
item._show = show;
if( item.identitylink?.state==2 || item.identitylink?.state==3 ){
show = false;
}
return item;
})
this.datas = data
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
},
//
approve(type){
$A.modalInput({
title: `审批`,
placeholder: `请输入审批意见`,
type:"textarea",
okText: type == 1 ? "同意" : "拒绝",
onOk: (desc) => {
if (type !=1 && !desc) {
return `请输入审批意见`
}
this.$store.dispatch("call", {
url: 'workflow/task/complete',
data: {
task_id: this.datas.task_id,
pass: type == 1,
comment: desc,
}
}).then(({msg}) => {
$A.messageSuccess(msg);
if(this.$route.name=='manage-review-details' || this.$route.name=='manage-messenger'){
this.getInfo()
}else{
this.$emit('approve')
}
}).catch(({msg}) => {
$A.modalError(msg);
});
return false
}
});
},
//
revocation(){
$A.modalConfirm({
content: "你确定要撤销吗?",
loading: true,
onOk: () => {
return new Promise((resolve, reject) => {
this.$store.dispatch("call", {
url: 'workflow/task/withdraw',
data: {
task_id: this.datas.task_id,
proc_inst_id: this.datas.id,
}
}).then(({msg}) => {
$A.messageSuccess(msg);
resolve();
if(this.$route.name=='manage-review-details' || this.$route.name=='manage-messenger'){
this.getInfo()
}else{
this.$emit('revocation')
}
}).catch(({msg}) => {
$A.modalError(msg);
resolve();
});
return false
})
},
});
},
//
comment(){
this.commentShow = true;
},
//
confirmComment(){
this.loadIng++;
this.$store.dispatch("call", {
method: 'post',
url: 'workflow/process/addGlobalComment',
data: {
proc_inst_id:this.data.id,
content:JSON.stringify({
'content': this.commentData.content,
'pictures': this.commentData.pictures.map(h =>{ return h.path; })
})
}
}).then(({msg}) => {
$A.messageSuccess("添加成功");
if(this.$route.name=='manage-review-details' || this.$route.name=='manage-messenger'){
this.getInfo()
}else{
this.$emit('approve')
}
this.commentShow = false;
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
},
//
getContent(content){
try {
return JSON.parse(content).content || ''
} catch (error) {
return ''
}
},
//
getPictures(content){
try {
return JSON.parse(content).pictures || []
} catch (error) {
return ''
}
},
//
onViewPicture(currentUrl) {
this.$store.dispatch("previewImage", '/' +currentUrl)
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,571 @@
<template>
<div class="page-review">
<PageTitle :title="$L('审批中心')"/>
<div class="review-wrapper" ref="fileWrapper">
<div class="review-head">
<div class="review-nav">
<h1>{{$L('审批中心')}}</h1>
</div>
<Button type="primary" @click="addApply">{{$L("添加申请")}}</Button>
<!-- <Button v-for="(item,key) in procdefList" :loading="loadIng > 0" :key="key" type="primary" @click="initiate(item)" style="margin-right:10px;">{{$L(item.name)}}</Button> -->
</div>
<Tabs :value="tabsValue" @on-click="tabsClick" style="margin: 0 20px;height: 100%;" size="small">
<TabPane :label="$L('待办') + (backlogTotal > 0 ? ('('+backlogTotal+')') : '')" name="backlog" style="height: 100%;">
<div class="review-main-search">
<div style="display: flex;gap: 10px;">
<Select v-model="approvalType" @on-change="tabsClick('',0)" style="width: 150px;">
<Option v-for="item in approvalList" :value="item.value" :key="item.value">{{ item.label }}</Option>
</Select>
</div>
</div>
<div class="noData" v-if="backlogList.length==0">{{$L('暂无数据')}}</div>
<div v-else class="review-mains">
<div class="review-main-left">
<div class="review-main-list">
<div @click.stop="clickList(item,key)" v-for="(item,key) in backlogList">
<list :class="{ 'review-list-active': item._active }" :data="item"></list>
</div>
</div>
</div>
<div class="review-main-right">
<listDetails v-if="!detailsShow && tabsValue=='backlog'" :data="details" @approve="tabsClick" @revocation="tabsClick"></listDetails>
</div>
</div>
</TabPane>
<TabPane :label="$L('已办')" name="done">
<div class="review-main-search">
<div style="display: flex;gap: 10px;">
<Select v-model="approvalType" @on-change="tabsClick('',0)" style="width: 150px;">
<Option v-for="item in approvalList" :value="item.value" :key="item.value">{{ item.label }}</Option>
</Select>
</div>
</div>
<div v-if="doneList.length==0" class="noData">{{$L('暂无数据')}}</div>
<div v-else class="review-mains">
<div class="review-main-left">
<div class="review-main-list">
<div @click.stop="clickList(item,key)" v-for="(item,key) in doneList" >
<list :class="{ 'review-list-active': item._active }" :data="item"></list>
</div>
</div>
</div>
<div class="review-main-right">
<listDetails v-if="!detailsShow && tabsValue=='done'" :data="details" @approve="tabsClick" @revocation="tabsClick"></listDetails>
</div>
</div>
</TabPane>
<TabPane :label="$L('抄送我')" name="notify">
<div class="review-main-search">
<div class="review-main-search">
<div style="display: flex;gap: 10px;">
<Select v-model="approvalType" @on-change="tabsClick('',0)" style="width: 150px;">
<Option v-for="item in approvalList" :value="item.value" :key="item.value">{{ item.label }}</Option>
</Select>
</div>
</div>
</div>
<div class="noData" v-if="notifyList.length==0">{{$L('暂无数据')}}</div>
<div v-else class="review-mains">
<div class="review-main-left">
<div class="review-main-list">
<div @click.stop="clickList(item,key)" v-for="(item,key) in notifyList">
<list :class="{ 'review-list-active': item._active }" :data="item"></list>
</div>
</div>
</div>
<div class="review-main-right">
<listDetails v-if="!detailsShow && tabsValue=='notify'" :data="details" @approve="tabsClick" @revocation="tabsClick"></listDetails>
</div>
</div>
</TabPane>
<TabPane :label="$L('已发起')" name="initiated">
<div class="review-main-search">
<div style="display: flex;gap: 10px;">
<Select v-model="approvalType" @on-change="tabsClick('',0)" style="width: 150px;">
<Option v-for="item in approvalList" :value="item.value" :key="item.value">{{ item.label }}</Option>
</Select>
<Select v-model="searchState" @on-change="tabsClick('',0)" style="width: 150px;">
<Option v-for="item in searchStateList" :value="item.value" :key="item.value">{{ item.label }}</Option>
</Select>
</div>
</div>
<div class="noData" v-if="initiatedList.length==0">{{$L('暂无数据')}}</div>
<div v-else class="review-mains">
<div class="review-main-left">
<div class="review-main-list">
<div @click.stop="clickList(item,key)" v-for="(item,key) in initiatedList">
<list :class="{ 'review-list-active': item._active }" :data="item"></list>
</div>
</div>
</div>
<div class="review-main-right">
<listDetails v-if="!detailsShow && tabsValue=='initiated'" :data="details" @approve="tabsClick" @revocation="tabsClick"></listDetails>
</div>
</div>
</TabPane>
</Tabs>
</div>
<!--详情-->
<DrawerOverlay v-model="detailsShow" placement="right" :size="600">
<listDetails v-if="detailsShow" :data="details" @approve="tabsClick" @revocation="tabsClick" style="height: 100%;border-radius: 10px;"></listDetails>
</DrawerOverlay>
<!--发起-->
<Modal v-model="addShow" :title="$L(addTitle)" :mask-closable="false" class="page-review-initiate">
<Form ref="initiateRef" :model="addData" :rules="addRule" label-width="auto" @submit.native.prevent>
<FormItem v-if="departmentList.length>1" prop="department_id" :label="$L('选择部门')">
<Select v-model="addData.department_id" :placeholder="$L('请选择部门')">
<Option v-for="(item, index) in departmentList" :value="item.id" :key="index">{{ item.name }}</Option>
</Select>
</FormItem>
<FormItem prop="applyType" :label="$L('申请类型')">
<Select v-model="addData.applyType" :placeholder="$L('请选择申请类型')">
<Option v-for="(item, index) in procdefList" :value="item.name" :key="index">{{ item.name }}</Option>
</Select>
</FormItem>
<FormItem v-if="(addData.applyType || '').indexOf('请假') !== -1" prop="type" :label="$L('假期类型')">
<Select v-model="addData.type" :placeholder="$L('请选择假期类型')">
<Option v-for="(item, index) in selectTypes" :value="item" :key="index">{{ $L(item) }}</Option>
</Select>
</FormItem>
<FormItem prop="startTime" :label="$L('开始时间')">
<div style="display: flex;gap: 3px;">
<DatePicker type="date" format="yyyy-MM-dd"
v-model="addData.startTime"
:editable="false"
@on-change="(e)=>{ addData.startTime = e }"
:placeholder="$L('请选择开始时间')"
style="flex: 1;min-width: 122px;"
></DatePicker>
<Select v-model="addData.startTimeHour" style="max-width: 100px;">
<Option v-for="(item,index) in 24" :value="item-1 < 10 ? '0'+(item-1) : item-1 " :key="index">{{item-1 < 10 ? '0' : ''}}{{item-1}}</Option>
</Select>
<Select v-model="addData.startTimeMinute" style="max-width: 100px;">
<Option value="00">00</Option>
<Option value="30">30</Option>
</Select>
</div>
</FormItem>
<FormItem prop="endTime" :label="$L('结束时间')">
<div style="display: flex;gap: 3px;">
<DatePicker type="date" format="yyyy-MM-dd"
v-model="addData.endTime"
:editable="false"
@on-change="(e)=>{ addData.endTime = e }"
:placeholder="$L('请选择结束时间')"
style="flex: 1;min-width: 122px;"
></DatePicker>
<Select v-model="addData.endTimeHour" style="max-width: 100px;">
<Option v-for="(item,index) in 24" :value="item-1 < 10 ? '0'+(item-1) : ((item-1)+'') " :key="index">{{item-1 < 10 ? '0' : ''}}{{item-1}}</Option>
</Select>
<Select v-model="addData.endTimeMinute" style="max-width: 100px;">
<Option value="00">00</Option>
<Option value="30">30</Option>
</Select>
</div>
</FormItem>
<FormItem prop="description" :label="$L('事由')">
<Input type="textarea" v-model="addData.description"></Input>
</FormItem>
<FormItem prop="other" :label="$L('图片')">
<ImgUpload v-model="addData.other" :num="3" :width="512" :height="512" :whcut="1"></ImgUpload>
</FormItem>
</Form>
<div slot="footer" class="adaption">
<Button type="default" @click="addShow=false">{{$L('取消')}}</Button>
<Button type="primary" :loading="loadIng > 0" @click="onInitiate">{{$L('确认')}}</Button>
</div>
</Modal>
</div>
</template>
<script>
import list from "./list.vue";
import listDetails from "./details.vue";
import DrawerOverlay from "../../../components/DrawerOverlay";
import ImgUpload from "../../../components/ImgUpload";
import { mapState } from 'vuex'
export default {
components:{list,listDetails,DrawerOverlay,ImgUpload},
name: "review",
data(){
return{
minDate: new Date(2020, 0, 1),
maxDate: new Date(2025, 10, 1),
currentDate: new Date(2021, 0, 17),
procdefList: [],
page: 1,
pageSize: 250,
total: 0,
noText: '',
loadIng:false,
tabsValue:"",
//
approvalType:"all",
approvalList:[
{value:"all",label:this.$L("全部审批")},
{value:"请假",label:this.$L("请假")},
{value:"加班申请",label:this.$L("加班申请")},
],
searchState:"all",
searchStateList:[
{value:"all",label:this.$L("全部状态")},
{value:1,label:this.$L("审批中")},
{value:2,label:this.$L("已通过")},
{value:3,label:this.$L("已拒绝")},
{value:4,label:this.$L("已撤回")}
],
//
backlogTotal:0,
backlogList: [],
doneList:[],
notifyList:[],
initiatedList: [],
//
details:{},
detailsShow:false,
//
addTitle:'',
addShow:false,
startTimeOpen:false,
endTimeOpen:false,
addData: {
department_id:0,
applyType: '',
type: '',
startTime: "2023-04-20",
startTimeHour:"09",
startTimeMinute:"00",
endTime: "2023-04-20",
endTimeHour:"18",
endTimeMinute:"00",
other:""
},
addRule: {
department_id:{ type: 'number',required: true, message: this.$L('请选择部门!'), trigger: 'change' },
applyType: { type: 'string',required: true, message: this.$L('请选择申请类型!'), trigger: 'change' },
type: { type: 'string',required: true, message: this.$L('请选择假期类型!'), trigger: 'change' },
startTime: { type: 'string',required: true, message: this.$L('请选择开始时间!'), trigger: 'change' },
endTime:{ type: 'string',required: true, message: this.$L('请选择结束时间!'), trigger: 'change' },
description:{ type: 'string',required: true, message: this.$L('请输入事由!'), trigger: 'change' },
},
selectTypes:["年假","事假","病假","调休","产假","陪产假","婚假","丧假","哺乳假"],
//
showDateTime:false
}
},
computed: {
...mapState([ 'wsMsg','userInfo','userIsAdmin' ]),
departmentList(){
let departmentNames = (this.userInfo.department_name || '').split(',');
return (this.userInfo.department || []).map((h,index)=>{
return {
id:h,
name:departmentNames[index]
};
})
}
},
watch: {
'$route' (to, from) {
if(to.name == 'manage-review'){
this.tabsClick()
}
},
wsMsg: {
handler(info) {
const {type, action} = info;
switch (type) {
case 'workflow':
if (action == 'backlog') {
this.tabsClick()
}
break;
}
},
deep: true,
},
addShow(val){
if(!val){
this.addData.other = ""
}
}
},
mounted() {
this.tabsValue = "backlog"
this.tabsClick()
this.getBacklogList()
this.addData.department_id = this.userInfo.department[0] || 0;
this.addData.startTime = this.addData.endTime = this.getCurrentDate();
},
methods:{
getCurrentDate() {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const date = String(today.getDate()).padStart(2, '0');
return `${year}-${month}-${date}`;
},
// tab
tabsClick(val,time= 1000){
if(!val && this.__tabsClick && time>0){
return;
}
this.__tabsClick = setTimeout(() => { this.__tabsClick =null; },time)
this.tabsValue = val || this.tabsValue
if(val!=""){
this.approvalType = this.searchState = "all"
}
if(this.tabsValue == 'backlog'){
this.getBacklogList();
}
if(this.tabsValue == 'done'){
this.getDoneList();
}
if(this.tabsValue == 'notify'){
this.getNotifyList();
}
if(this.tabsValue == 'initiated'){
this.getInitiatedList();
}
},
//
clickList(item){
this.backlogList.map(h=>{ h._active = false; })
this.doneList.map(h=>{ h._active = false; })
this.notifyList.map(h=>{ h._active = false; })
this.initiatedList.map(h=>{ h._active = false; })
item._active = true;
//
if( window.innerWidth < 426 ){
this.goForward({name: 'manage-review-details', query: { id: item.id } });
return;
}
if( window.innerWidth < 1010 ){
this.detailsShow = true;
}
this.details = {}
this.$nextTick(()=>{
this.details = item
})
},
//
getBacklogList(){
this.$store.dispatch("call", {
method: 'get',
url: 'workflow/process/findTask',
data: {
page:this.page,
page_size: this.pageSize,
proc_def_name: this.approvalType == 'all' ? '' : this.approvalType,
}
}).then(({data}) => {
this.backlogList = data.rows.map((h,index)=>{
h._active = index == 0;
return h;
})
if(this.approvalType == 'all'){
this.backlogTotal = this.backlogList.length
}
if(this.tabsValue == 'backlog'){
this.$nextTick(()=>{
this.details = this.backlogList[0] || {}
})
}
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
},
//
getDoneList(){
this.$store.dispatch("call", {
method: 'get',
url: 'workflow/procHistory/findTask',
data: {
page:this.page,
page_size: this.pageSize,
proc_def_name: this.approvalType == 'all' ? '' : this.approvalType,
}
}).then(({data}) => {
this.doneList = data.rows.map((h,index)=>{
h._active = index == 0;
return h;
})
if(this.tabsValue == 'done'){
this.$nextTick(()=>{
this.details = this.doneList[0] || {}
})
}
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
},
//
getNotifyList(){
this.$store.dispatch("call", {
method: 'get',
url: 'workflow/procHistory/findProcNotify',
data: {
page:this.page,
page_size: this.pageSize,
proc_def_name: this.approvalType == 'all' ? '' : this.approvalType,
}
}).then(({data}) => {
this.notifyList = data.rows.map((h,index)=>{
h._active = index == 0;
return h;
})
if(this.tabsValue == 'notify'){
this.$nextTick(()=>{
this.details = this.notifyList[0] || {}
})
}
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
},
//
getInitiatedList(){
this.$store.dispatch("call", {
method: 'post',
url: 'workflow/process/startByMyselfAll',
data: {
page: this.page,
page_size: this.pageSize,
proc_def_name: this.approvalType == 'all' ? '' : this.approvalType,
state: this.searchState == 'all' ? '' : this.searchState
}
}).then(({data}) => {
this.initiatedList = data.rows.map((h,index)=>{
h._active = index == 0;
return h;
})
if(this.tabsValue == 'initiated'){
this.$nextTick(()=>{
this.details = this.initiatedList[0] || {}
})
}
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
},
//
addApply(){
this.$store.dispatch("call", {
url: 'users/basic',
data: {
userid: [ this.userInfo.userid]
},
skipAuthError: true
}).then(({data}) => {
this.addData.department_id = data[0]?.department[0] || 0;
if( !this.addData.department_id ){
$A.modalError("您当前未加入任何部门,不能发起!");
return false;
}
this.$store.dispatch("call", {
url: 'workflow/procdef/all',
method: 'post',
}).then(({data}) => {
this.procdefList = data.rows || [];
this.addTitle = this.$L("添加申请");
this.addShow = true;
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
},
//
onInitiate(){
this.$refs.initiateRef.validate((valid) => {
if (valid) {
this.loadIng = 1;
var obj = JSON.parse(JSON.stringify(this.addData))
obj.startTime = obj.startTime +" "+ obj.startTimeHour + ":" + obj.startTimeMinute;
obj.endTime = obj.endTime +" "+ obj.endTimeHour + ":" + obj.endTimeMinute;
if(this.addData.other){
obj.other = this.addData.other.map((o) =>{
return o.path
}).join(',')
}
this.$store.dispatch("call", {
url: 'workflow/process/start',
data: {
proc_name: obj.applyType,
department_id: obj.department_id,
var: JSON.stringify(obj),
},
method: 'post',
}).then(({data, msg}) => {
$A.messageSuccess(msg);
this.addShow = false;
this.$refs.initiateRef.resetFields();
this.tabsClick();
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
}
});
}
},
}
</script>
<style lang="scss">
.page-review .review-details{
border-radius: 8px;
}
.page-review .ivu-tabs-nav {
display: flex;
width: 350px;
@media (max-width: 1010px) {
width: 100%;
}
.ivu-tabs-tab{
font-size: 15px;
flex:1;
text-align: center;
}
}
.page-review-initiate .ivu-modal-body{
padding: 16px 22px 2px !important;
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<div class="review-list">
<h2>
<span class="list-name">{{$L(data.proc_def_name)}}</span>
<Tag v-if="data.state == 0" color="cyan">{{$L('待审批')}}</Tag>
<Tag v-if="data.state == 1" color="cyan">{{$L('审批中')}}</Tag>
<Tag v-if="data.state == 2" color="green">{{$L('已通过')}}</Tag>
<Tag v-if="data.state == 3" color="red">{{$L('已拒绝')}}</Tag>
<Tag v-if="data.state == 4" color="red">{{$L('已撤回')}}</Tag>
</h2>
<p v-if="data.var?.type">{{$L('假期类型')}}<span>{{$L(data.var?.type)}}</span></p>
<p>{{$L('开始时间')}}<span>{{data.var?.start_time}}</span></p>
<p>{{$L('结束时间')}}<span>{{data.var?.end_time}}</span></p>
<div class="list-member">
<span>
<Avatar :src="data.userimg" size="20"/>
{{ data.start_user_name }}
</span>
<span>
{{$L('发起时间')}}{{data.start_time}}
</span>
</div>
</div>
</template>
<script>
export default {
name: "list",
props: {
data: {
type: Object,
default() {
return {};
}
}
},
data() {
return {
}
}
}
</script>

View File

@ -0,0 +1,185 @@
<template>
<div class="setting-item submit">
<Row class="approve-row" :gutter="8">
<Col :xxl="{ span: 6 }" :xl="{ span: 8 }" :lg="{ span: 12 }" :sm="{ span: 24 }" :xs="{ span: 24 }" >
<div class="approve-col-box approve-col-add" @click="add">
<Icon type="md-add" />
</div>
</Col>
<Col v-for="(item, key) in list" :xxl="{ span: 6 }" :xl="{ span: 8 }" :lg="{ span: 12 }" :sm="{ span: 24 }" :xs="{ span: 24 }" >
<div class="approve-col-box approve-col-for" @click="edit(item)">
<p>{{$L('流程名称')}}<span style="font-weight: 500;color: #135de6;">{{$L(item.name)}}</span></p>
<Divider style="margin: 12px 0;margin-bottom: 9px;"/>
<div class="approve-button-box" @click.stop="edit(item)">
<p>{{$L('已发布')}}</p>
<p @click.stop="change(item)" style="position: relative;">
<Icon type="md-trash" size="16" class="delcon"/>
</p>
<!-- <p>{{$L('是否发布')}} </p>
<p @click.stop="!item.issue ? edit(item) : ''">
<i-switch v-model="item.issue" @on-change="change(item)" :disabled="true" />
</p> -->
</div>
</div>
</Col>
</Row>
<!--查看所有项目-->
<DrawerOverlay v-model="approvalSettingShow" placement="right" :size="1200">
<iframe :src="iframeSrc"></iframe>
</DrawerOverlay>
</div>
</template>
<script>
import DrawerOverlay from "../../../components/DrawerOverlay";
import store from '../../../store/state'
import {languageType} from "../../../language";
export default {
name: "approve",
components: {DrawerOverlay},
data(){
return{
value:false,
loadIng:0,
approvalSettingShow:false,
iframeSrc:"",
name:"",
list:[
// {id:0,name:"",issue:false,version:''},
// {id:0,name:"",issue:false,version:''},
]
}
},
watch: {
approvalSettingShow(val) {
if (val) this.iframeSrc = `/workflow/#/?name=${this.name}&token=${store.userToken}&lang=${languageType}`
}
},
mounted() {
window.addEventListener('message', this.saveSuccess)
this.getList();
},
beforeDestroy() {
window.removeEventListener("message", this.saveSuccess);
},
methods: {
//
getList(){
this.$store.dispatch("call", {
url: 'workflow/procdef/all',
method: 'post',
}).then(({data}) => {
this.list = data.rows;
data.rows.forEach((h,index) => {
this.list.forEach((o,index) => {
if(o.name == h.name){
o.issue = true;
o.id = h.id;
o.version = h.version;
}
})
})
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
},
//
saveSuccess(e){
if (typeof e.data === 'string') {
let propsBody = JSON.parse(e.data);
if( propsBody.method == "saveSuccess" ) {
this.getList();
this.list.forEach((h,index) => {
if(h.name == this.name){
h.issue = true;
this.$set(this.list,index,h)
}
});
this.approvalSettingShow = false;
$A.messageSuccess('发布成功');
}
}
},
//
add(){
$A.modalInput({
title: `添加流程`,
placeholder: `请输入流程名称`,
type:"textarea",
okText: "确定",
onOk: (desc) => {
if (!desc) {
return `请输入流程名称`
}
this.name = desc
this.approvalSettingShow = true;
return false
}
});
},
//
edit(item){
this.name = item.name
this.approvalSettingShow = true;
},
//
change(item){
this.$nextTick(()=>{
item.issue = true;
$A.modalConfirm({
title: '删除',
content: '将会清空流程数据,此操作不可恢复',
onOk: () => {
this.del(item)
}
});
});
},
//
del(item){
if(!item.id){
item.issue = false;
return true;
}
this.$store.dispatch("call", {
url: 'workflow/procdef/del',
data: {id: item.id},
method: 'post',
}).then(({data}) => {
item.issue = false;
this.getList();
$A.messageSuccess('成功');
}).catch(({msg}) => {
$A.modalError(msg);
}).finally(_ => {
this.loadIng--;
});
},
}
}
</script>
<style scoped>
iframe{
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: 0;
float: left;
border-top-left-radius: 18px;
border-bottom-left-radius: 18px;
}
.delcon{
position: absolute;
right: 0;
padding: 5px !important;
}
.delcon:hover{
color: #ed4014 !important;
}
</style>

View File

@ -93,6 +93,7 @@ export default {
if (this.userIsAdmin) {
menu.push(...[
{path: 'system', name: '系统设置', divided: true},
{path: 'approve', name: this.$L('审批设置'), desc: ' (Beta)'},
{path: 'license', name: 'License Key'},
])
}

View File

@ -29,6 +29,16 @@ export default [
path: 'messenger/:dialogAction?',
component: () => import('./pages/manage/messenger.vue'),
},
{
name: 'manage-review',//审批
path: 'review',
component: () => import('./pages/manage/review/index.vue'),
},
{
name: 'manage-review-details',
path: 'review/details',
component: () => import('./pages/manage/review/details.vue'),
},
{
name: 'manage-setting',
path: 'setting',
@ -44,6 +54,11 @@ export default [
path: 'checkin',
component: () => import('./pages/manage/setting/checkin.vue'),
},
{
name: 'manage-setting-approve',
path: 'approve',
component: () => import('./pages/manage/setting/approve.vue'),
},
{
name: 'manage-setting-language',
path: 'language',

View File

@ -466,6 +466,7 @@ export default {
dispatch("getProjects").catch(() => {});
dispatch("getDialogs").catch(() => {});
dispatch("getReportUnread", 1000);
dispatch("getBacklogUnread", 1000);
dispatch("getTaskForDashboard");
dispatch("dialogMsgRead");
//
@ -494,6 +495,32 @@ export default {
}, typeof timeout === "number" ? timeout : 1000)
},
/**
* 获取审批待办未读数量
* @param state
* @param dispatch
* @param timeout
*/
getBacklogUnread({state, dispatch}, timeout) {
window.__getBacklogUnread && clearTimeout(window.__getBacklogUnread)
window.__getBacklogUnread = setTimeout(() => {
if (state.userId === 0) {
state.backlogUnreadNumber = 0;
} else {
dispatch("call", {
url: 'workflow/process/findTask',
data: {
page:1,
page_size: 500,
}
}).then(({data}) => {
state.backlogUnreadNumber = data.total || 0;
}).catch(_ => {});
}
}, typeof timeout === "number" ? timeout : 1000)
},
/**
* 获取/更新会员信息
* @param dispatch

View File

@ -191,4 +191,7 @@ export default {
apiKeyData: {},
localKeyPair: {},
localKeyLock: false,
// 审批待办未读数量
backlogUnreadNumber: 0,
};

View File

@ -175,6 +175,12 @@ body.dark-mode-reverse {
.content-meeting {
color: #ffffff;
}
.open-review-details{
.cause{
border-bottom: 1px solid #7f7f7f;
border-top: 1px solid #7f7f7f;
}
}
}
.dialog-emoji {
> li {

View File

@ -9,3 +9,4 @@
@import "page-setting";
@import "page-index";
@import "components/_";
@import "page-review";

View File

@ -704,6 +704,41 @@
background-color: $primary-color;
}
}
.open-review-details{
width: 245px;
display: inline-block;
max-width: 100%;
.cause{
border-bottom: 1px solid #e3e3e3;
border-top: 1px solid #e3e3e3;
padding-bottom: 10px;
margin-top: 10px;
>span:first-child{
display: inline-block;
padding: 15px 0;
}
>b{
display: inline-block;
margin-bottom: 5px;
}
>span{
display: inline-block;
margin-bottom: 3px;
}
}
.btn-raw{
display: flex;
text-align: center;
padding: 12px 0 5px 0;
>button.ivu-btn-primary{
margin-right: 12px;
}
>button.ivu-btn-small{
height: 32px;
}
}
}
}
}

View File

@ -0,0 +1,279 @@
.page-review{
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.review-wrapper {
flex: 1;
height: 0;
display: flex;
flex-direction: column;
position: relative;
.review-head {
display: flex;
align-items: center;
padding-bottom: 16px;
margin: 32px 20px 16px;
margin-bottom: 5px;
border-bottom: 1px solid #F4F4F5;
.review-nav{
flex: 1;
display: flex;
align-items: center;
> h1 {
color: $primary-title-color;
font-size: 28px;
font-weight: 600;
}
}
}
.review-main-search{
display: flex;
justify-content: space-between;
margin:0 5px;
margin-bottom: 10px;
> div{
.ivu-dropdown{
margin-right: 8px;
}
}
}
.noData{
text-align: center;
line-height: 150px;
}
.review-mains{
display: flex;
flex: 1 1 auto;
height: calc(100vh - 190px);
position: relative;
.review-main-left{
display: flex;
flex-direction: column;
flex: 0 0 auto;
position: absolute;
left: 0;
top: 0;
bottom: 12px;
max-width: 360px;
width: 100%;
@media (max-width: 1010px) {
max-width: 100%;
}
.review-main-list{
display: flex;
flex-direction: column;
flex: 1 1 auto;
overflow: scroll;
.review-list{
margin-bottom: 8px;
padding: 12px;
border-radius: 8px;
border: 1px solid #eeeeee;
transition: box-shadow 0.3s;
cursor: pointer;
&:hover{
box-shadow: 0 0 10px #e6ecfa;
}
> h2{
display: flex;
align-items: center;
justify-content: space-between;
> .list-name{
font-size: 14px;
font-weight: bold;
}
}
> p{
font-size: 14px;
margin-top: 5px;
> span{
color: #303133;
}
}
.list-member{
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10px;
> span {
display: flex;
align-items: center;
font-size: 12px;
.ivu-avatar {
margin-right: 8px;
}
}
}
}
.review-list-active{
border: 1px solid #8bcf70;
}
}
.review-main-list::-webkit-scrollbar {
display: none;
}
}
.review-main-right{
position: absolute;
left: 360px;
top: 0;
right: 0;
bottom: 0;
flex: 1 1 auto;
display: flex;
margin: 0 0 12px 12px;
@media (max-width: 1010px) {
display: none;
}
}
}
}
}
.review-details{
flex: 1 1 auto;
display: flex;
flex-direction: column;
border: 1px solid #eeeeee;
background: #fff;
.review-details-box{
flex: 1 1 auto;
padding: 24px;
overflow-y: scroll;
.review-details-title{
display: flex;
align-items: center;
.ivu-tag{
margin-left: 8px;
}
}
.review-details-subtitle{
margin-top: 8px;
display: flex;
.ivu-avatar{
margin-right: 8px;
}
> span{
font-size: 14px;
}
}
.timeline-title{
font-weight: bold;
padding-bottom: 10px;
}
.review-details-text{
margin-bottom: 12px;
> h4{
color: #999;
}
> p{
font-size: 14px;
margin-top: 2px;
font-weight: 500;
}
.img-body{
display: flex;
gap: 10px;
margin-top: 3px;
}
}
.review-record-timeline{
margin-top: 20px;
.timeline-body{
display: flex;
}
.review-process-state{
font-size: 12px;
color: #19be6b;
}
.review-process-left{
margin-left: 10px;
flex: 1;
}
.review-process-right{
text-align: right;
}
}
.review-record-comment{
padding: 10px;
margin-bottom: 30px;
.top{
display: flex;
gap: 8px;
}
.time{
font-size: 12px;
color: #a2a2a2;
}
.content{
margin-top: 3px;
padding-left: 45px;
}
}
.review-details-text:nth-last-child(1){
margin-bottom: 0;
}
.img-view{
max-width: 60px;
border-radius: 5px;
}
.review-copy{
margin-top: 8px;
display: flex;
.review-copy-member{
display: flex;
align-items: center;
background: #F4F4F5;
padding:2px 8px;
border-radius: 20px;
.ivu-avatar{
margin-right: 4px;
}
}
}
}
.review-details-box::-webkit-scrollbar {
display: none;
}
.review-operation{
flex: 0 0 auto;
padding: 0 24px;
border-top: 1px solid #F4F4F5;
display: flex;
align-items: center;
button{
margin: 10px 0;
margin-left: 10px;
}
}
.comment{
margin-top: 5px;
margin-left: 45px;
span{
background-color: #eaeaea;
border-radius: 5px;
padding: 3px 10px;
display: inline-block;
}
}
}

View File

@ -349,6 +349,55 @@
.setting-button {
margin-left: 8px;
}
.approve-row{
padding: 24px 40px;
overflow: auto;
.ivu-col{
margin-bottom: 8px;
.approve-col-box{
border-radius: 8px;
border: 1px solid #eeeeee;
transition: box-shadow 0.3s;
cursor: pointer;
&:hover{
box-shadow: 0 0 10px #e6ecfa;
}
}
.approve-col-add{
height: 100%;
font-size: 48px;
display: flex;
justify-content: center;
align-items: center;
color: #ededed;
}
.approve-col-for{
padding:16px;
padding-bottom:13px;
display: flex;
flex-direction: column;
> p{
display: flex;
align-items: center;
}
.approve-button-box{
display: flex;
justify-content: space-between;
align-items: center;
> p {
display: flex;
align-items: center;
> i {
font-size: 16px;
margin-left: 8px;
color: rgb(96, 98, 102);
}
}
}
}
}
}
}
}
}

View File

@ -108,6 +108,61 @@
<span style="color:#84c56a">version</span>: 系统版本
@elseif ($type === 'notice')
{{$notice}}
@elseif ($type === 'workflow_reviewer')
<span class="open-review-details" data-id="{{$data->id}}"><b>{{$data->nickname}}提交的「{{$data->proc_def_name}}」待你审批</b>
<div class="cause"><span>申请人:<span style="color:#84c56a">{{'@'}}{{$data->nickname}}</span> {{$data->department}}</span>
<b>审批事由</b>
@if ($data->type)
<span>假期类型:{{$data->type}}</span>
@endif
<span>开始时间:{{$data->start_time}}</span>
<span>结束时间:{{$data->end_time}}</span>
</div><div class="btn-raw">
@if ($action === 'pass')
<Button type="button" class="ivu-btn" style="flex: 1;">已同意</Button>
@elseif ($action === 'refuse')
<Button type="button" class="ivu-btn" style="flex: 1;">已拒绝</Button>
@elseif ($action === 'withdraw')
<Button type="button" class="ivu-btn" style="flex: 1;">已撤销</Button>
@else
<Button type="button" class="ivu-btn ivu-btn-primary" style="flex: 1;">同意</Button>
<Button type="button" class="ivu-btn ivu-btn-error" style="flex: 1;">拒绝</Button>
@endif
</div></span>
@elseif ($type === 'workflow_notifier')
<span class="open-review-details" data-id="{{$data->id}}"><b>抄送{{$data->nickname}}提交的「{{$data->proc_def_name}}」记录</b>
<div class="cause"><span>申请人:<span style="color:#84c56a">{{'@'}}{{$data->nickname}}</span> {{$data->department}}</span>
<b>审批事由</b>
@if ($data->type)
<span>假期类型:{{$data->type}}</span>
@endif
<span>开始时间:{{$data->start_time}}</span>
<span>结束时间:{{$data->end_time}}</span>
</div><div class="btn-raw">
@if ($is_finished == 1)
<Button type="button" class="ivu-btn" style="flex: 1;">已同意</Button>
@else
<Button type="button" class="ivu-btn" style="flex: 1;">查看详情</Button>
@endif
</div></span>
@elseif ($type === 'workflow_submitter')
<span class="open-review-details" data-id="{{$data->id}}"><b> @if ($action === 'pass')您发起的「{{$data->proc_def_name}}」已通过 @else您发起的「{{$data->proc_def_name}}」被{{$data->nickname}}拒绝 @endif</b>
<div class="cause"><span>申请人:<span style="color:#84c56a">{{'@'}}{{$data->nickname}}</span> {{$data->department}}</span>
<b>审批事由</b>
@if ($data->type)
<span>假期类型:{{$data->type}}</span>
@endif
<span>开始时间:{{$data->start_time}}</span>
<span>结束时间:{{$data->end_time}}</span>
</div><div class="btn-raw">
@if ($action === 'pass')
<Button type="button" class="ivu-btn" style="flex: 1;">已同意</Button>
@elseif ($action === 'refuse')
<Button type="button" class="ivu-btn" style="flex: 1;">已拒绝</Button>
@elseif ($action === 'withdraw')
<Button type="button" class="ivu-btn" style="flex: 1;">已撤销</Button>
@endif
</div></span>
@else
你好,我是你的机器人助理,你可以发送 <span style="color:#84c56a">/help</span> 查看帮助菜单。
@endif

View File

@ -1,14 +1,15 @@
<?php
use App\Http\Controllers\Api\DialogController;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\IndexController;
use App\Http\Controllers\Api\FileController;
use App\Http\Controllers\Api\ProjectController;
use App\Http\Controllers\Api\UsersController;
use App\Http\Controllers\Api\DialogController;
use App\Http\Controllers\Api\PublicController;
use App\Http\Controllers\Api\ReportController;
use App\Http\Controllers\Api\SystemController;
use App\Http\Controllers\Api\UsersController;
use App\Http\Controllers\IndexController;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\ProjectController;
use App\Http\Controllers\Api\WorkflowController;
/*
|--------------------------------------------------------------------------
@ -47,6 +48,9 @@ Route::prefix('api')->middleware(['webapi'])->group(function () {
// 公开接口
Route::any('public/{method}', PublicController::class);
Route::any('public/{method}/{action}', PublicController::class);
// 工作流
Route::any('workflow/{method}', WorkflowController::class);
Route::any('workflow/{method}/{action}', WorkflowController::class);
});
/**