Compare commits
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fd8d44a6e | ||
|
|
64262134c4 | ||
|
|
0019c9ef41 | ||
|
|
2676ebd047 | ||
|
|
97cdd56110 | ||
|
|
d973451bdc | ||
|
|
80313f613e | ||
|
|
5c564524a3 | ||
|
|
e081fbd92b | ||
|
|
0ecc20472a | ||
|
|
b51052f0c6 | ||
|
|
cb106e42ee | ||
|
|
52f9495ff8 | ||
|
|
440b633bad | ||
|
|
a07913181a | ||
|
|
34ffd96c86 | ||
|
|
46a623b430 | ||
|
|
c16e37023c | ||
|
|
1cb0cdf540 | ||
|
|
073d03a882 | ||
|
|
30b9276ab4 | ||
|
|
76c8b4a4c6 | ||
|
|
9ea4781d93 | ||
|
|
07d583f73f | ||
|
|
12c74aef7a | ||
|
|
64b10e3060 | ||
|
|
ab2b29f267 | ||
|
|
be9a968ad9 | ||
|
|
5f87067a75 | ||
|
|
ef273bd9dd | ||
|
|
0737a9fae7 | ||
|
|
727d7e1d81 | ||
|
|
87e8589aea | ||
|
|
b13758d3e9 | ||
|
|
14775e2861 | ||
|
|
94af3822d8 | ||
|
|
07254c9f27 | ||
|
|
a99c2f6944 | ||
|
|
f9540b08cd | ||
|
|
34af77eb6d | ||
|
|
cf3f22776c | ||
|
|
5bebc8b5ee | ||
|
|
8a4b0c57f9 | ||
|
|
1acfd7ee34 | ||
|
|
a29661c54d | ||
|
|
90558d5ece | ||
|
|
e6c7007be5 | ||
|
|
16d0d1687f | ||
|
|
95ab44d118 | ||
|
|
e541757b76 | ||
|
|
f422aea330 | ||
|
|
d5eb3716aa | ||
|
|
7fb854fb48 | ||
|
|
60b5ecdcd7 | ||
|
|
6cce7d31ff | ||
|
|
46f5dd99a6 | ||
|
|
9753dec996 | ||
|
|
53f2e07178 | ||
|
|
3aa2c604d8 | ||
|
|
d8fbf36e00 | ||
|
|
008653e3d9 | ||
|
|
23188777fe | ||
|
|
8eb0a49ee6 | ||
|
|
207f09a4af | ||
|
|
69120c5045 | ||
|
|
b8143d1a9b | ||
|
|
f7eab5893a | ||
|
|
5fc598a220 | ||
|
|
783c21ad18 | ||
|
|
a1ce6e6928 | ||
|
|
8cbae629a5 | ||
|
|
da7e832f21 | ||
|
|
a572ba0523 | ||
|
|
85a20168dc | ||
|
|
25be9c0fef | ||
|
|
a8c890ba51 | ||
|
|
11628b98ca | ||
|
|
4ae6ca945b | ||
|
|
49aa1434aa | ||
|
|
9e92c61fbf | ||
|
|
c84111b6b9 | ||
|
|
3a2fcdd18a | ||
|
|
84a800f69b | ||
|
|
77e08aa048 | ||
|
|
0d6fd903f1 | ||
|
|
bcc74dd927 | ||
|
|
dd0720afa7 | ||
|
|
a06a4095b6 | ||
|
|
29bc009c07 | ||
|
|
520d2a0e20 | ||
|
|
dbeb9dd561 | ||
|
|
5b02d8008f | ||
|
|
a032c6114f | ||
|
|
69ec4966d5 | ||
|
|
87fab80ea3 | ||
|
|
bd2dabe851 | ||
|
|
4a45d69e5b | ||
|
|
e15bea9342 | ||
|
|
7132413837 |
1
.gitignore
vendored
@@ -15,6 +15,7 @@
|
||||
.idea
|
||||
.vscode
|
||||
.vagrant
|
||||
.windsurfrules
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
|
||||
111
CHANGELOG.md
@@ -2,6 +2,117 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.42.57]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 跨地区发消息出现消息过期的情况
|
||||
- 多线程下载文件损坏的问题
|
||||
- 修复新建周报或日报唯一标识重复
|
||||
|
||||
### Features
|
||||
|
||||
- 添加 DeepSeek AI
|
||||
- 添加https证书自动更新
|
||||
|
||||
### Performance
|
||||
|
||||
- 支持自定义仪表盘欢迎词
|
||||
- ChatGPT 支持自定义 Base URL
|
||||
- 优化仪表盘任务更新规则
|
||||
|
||||
## [0.42.37]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 部分电脑无法复制的问题
|
||||
- 修复任务可见性 - 任务重覆获取, 子任务负责人看不到任务问题
|
||||
|
||||
### Performance
|
||||
|
||||
- 更新小海豚表情包
|
||||
- 优化任务时间冲突提示
|
||||
- 优化消息
|
||||
- 群聊总人数排除机器人
|
||||
|
||||
## [0.42.26]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 移交账号后工作流的负责人没有更新
|
||||
- 全屏预览时深色皮肤反色的情况
|
||||
|
||||
### Features
|
||||
|
||||
- 替换网页的资源为本地资源
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化任务面板
|
||||
- 优化子任务的可见性
|
||||
- 优化客户端
|
||||
- 优化会议
|
||||
- 优化会员搜索
|
||||
- 优化打开会话
|
||||
- 优化项目面板任务加载
|
||||
- 优化客户端加载
|
||||
|
||||
## [0.42.3]
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化对话阅读状况
|
||||
- 优化表情回复
|
||||
|
||||
## [0.42.0]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 桌面端查看表情图片缩略图显示错误
|
||||
- 项目面板任务不显示的情况
|
||||
- 修复移动任务子任务不跟随的情况
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化桌面端数据处理
|
||||
- 优化资源
|
||||
- 优化数据流
|
||||
|
||||
## [0.41.93]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 复制文件权限判断
|
||||
|
||||
### Performance
|
||||
|
||||
- AI创建任务确认
|
||||
- 优化项目面板
|
||||
|
||||
## [0.41.84]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- @在线状态不正确
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化子任务上下文
|
||||
- 优化子任务时间调整
|
||||
- 优化超长文本信息
|
||||
- 记录版本信息
|
||||
- 支持更多办公文件格式
|
||||
- 请假或外出时取消打卡提醒
|
||||
- 图片容错处理
|
||||
- 优化全局监听事件
|
||||
- 优化数据流消息
|
||||
|
||||
## [0.41.64]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 修复使用AI创建任务顺序错误的问题
|
||||
|
||||
## [0.41.55]
|
||||
|
||||
### Performance
|
||||
|
||||
10
README.md
@@ -47,16 +47,6 @@ cd dootask
|
||||
./cmd port 80
|
||||
```
|
||||
|
||||
### Change App Url
|
||||
|
||||
```bash
|
||||
# This URL only affects the email reply.
|
||||
./cmd url {Your domain url}
|
||||
|
||||
# example:
|
||||
./cmd url https://domain.com
|
||||
```
|
||||
|
||||
### Stop server
|
||||
|
||||
```bash
|
||||
|
||||
10
README_CN.md
@@ -47,16 +47,6 @@ cd dootask
|
||||
./cmd port 80
|
||||
```
|
||||
|
||||
### 更换URL
|
||||
|
||||
```bash
|
||||
# 此地址仅影响邮件回复功能
|
||||
./cmd url {域名地址}
|
||||
|
||||
# 例如:
|
||||
./cmd url https://domain.com
|
||||
```
|
||||
|
||||
### 停止服务
|
||||
|
||||
```bash
|
||||
|
||||
@@ -223,6 +223,19 @@ class Handler extends ExceptionHandler
|
||||
} catch (\ImagickException) { }
|
||||
}
|
||||
|
||||
// 容错处理
|
||||
$patternFault = '/^(images\/.*\.(png|jpg|jpeg))\/crop\/([^\/]+)$/';
|
||||
$matchesFault = null;
|
||||
if (preg_match($patternFault, $path, $matchesFault)) {
|
||||
$file = public_path($matchesFault[1]);
|
||||
if (!file_exists($file)) {
|
||||
$file = public_path('images/other/imgerr.jpg');
|
||||
}
|
||||
if (file_exists($file)) {
|
||||
return response()->file($file);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Tasks\PushTask;
|
||||
use App\Module\BillExport;
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Models\ApproveProcMsg;
|
||||
use App\Models\ApproveProcInstHistory;
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Models\UserDepartment;
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
@@ -1146,13 +1147,9 @@ class ApproveController extends AbstractController
|
||||
*/
|
||||
public function user__status()
|
||||
{
|
||||
$data['userid'] = intval(Request::input('userid'));
|
||||
$ret = Ihttp::ihttp_get($this->flow_url . '/api/v1/workflow/process/getUserApprovalStatus?' . http_build_query($data));
|
||||
$procdef = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (isset($procdef['status']) && $procdef['status'] == 200) {
|
||||
return Base::retSuccess('success', $procdef['data']["proc_def_name"] ?? '');
|
||||
}
|
||||
return Base::retSuccess('success', '');
|
||||
$userid = intval(Request::input('userid'));
|
||||
$status = ApproveProcInstHistory::getUserApprovalStatus($userid);
|
||||
return Base::retSuccess('success', $status);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,8 @@ use App\Module\Base;
|
||||
use App\Module\Timer;
|
||||
use App\Module\Extranet;
|
||||
use App\Module\TimeRange;
|
||||
use App\Module\MsgTool;
|
||||
use App\Module\Table\OnlineData;
|
||||
use App\Models\FileContent;
|
||||
use App\Models\AbstractModel;
|
||||
use App\Models\WebSocketDialog;
|
||||
@@ -288,6 +290,9 @@ class DialogController extends AbstractController
|
||||
$array = array_filter($data->toArray(), function ($item) {
|
||||
return $item['userid'] > 0;
|
||||
});
|
||||
foreach ($array as &$item) {
|
||||
$item['online'] = $item['bot'] || OnlineData::live($item['userid']) > 0;
|
||||
}
|
||||
} else {
|
||||
$data = WebSocketDialogUser::select(['web_socket_dialog_users.*', 'users.bot'])
|
||||
->join('users', 'web_socket_dialog_users.userid', '=', 'users.userid')
|
||||
@@ -1056,7 +1061,11 @@ class DialogController extends AbstractController
|
||||
} elseif ($reply_id > 0) {
|
||||
$action = "reply-$reply_id";
|
||||
if ($reply_check === 'yes') {
|
||||
$exisUserMsg = WebSocketDialogMsg::whereDialogId($dialog_id)->where('id', '>', $reply_id)->whereBot(0)->exists();
|
||||
$exisUserMsg = WebSocketDialogMsg::whereDialogId($dialog_id)
|
||||
->where('id', '>', $reply_id)
|
||||
->whereBot(0)
|
||||
->whereNotIn('type', ['notice', 'template'])
|
||||
->exists();
|
||||
if (!$exisUserMsg) {
|
||||
$action = "";
|
||||
}
|
||||
@@ -1088,21 +1097,29 @@ class DialogController extends AbstractController
|
||||
return Base::retError('消息发送保存失败');
|
||||
}
|
||||
$ext = $markdown ? 'md' : 'htm';
|
||||
$fileData = [
|
||||
'name' => "LongText-{$strlen}.{$ext}",
|
||||
'size' => $size,
|
||||
'file' => $file,
|
||||
'path' => $path,
|
||||
'url' => Base::fillUrl($path),
|
||||
'thumb' => '',
|
||||
'width' => -1,
|
||||
'height' => -1,
|
||||
'ext' => $ext,
|
||||
$text = MsgTool::truncateText($text, 500, $ext);
|
||||
$desc = strip_tags($markdown ? Base::markdown2html($text) : $text);
|
||||
$desc = mb_substr(WebSocketDialogMsg::filterEscape($desc), 0, 200);
|
||||
$msgData = [
|
||||
'desc' => $desc, // 描述内容
|
||||
'text' => $text, // 简要内容
|
||||
'type' => $ext, // 内容类型
|
||||
'file' => [
|
||||
'name' => "LongText-{$strlen}.{$ext}",
|
||||
'size' => $size,
|
||||
'file' => $file,
|
||||
'path' => $path,
|
||||
'url' => Base::fillUrl($path),
|
||||
'thumb' => '',
|
||||
'width' => -1,
|
||||
'height' => -1,
|
||||
'ext' => $ext,
|
||||
],
|
||||
];
|
||||
if (empty($key)) {
|
||||
$key = mb_substr(strip_tags($text), 0, 200);
|
||||
$key = $desc;
|
||||
}
|
||||
$result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'file', $fileData, $user->userid, false, false, $silence, $key);
|
||||
$result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'longtext', $msgData, $user->userid, false, false, $silence, $key);
|
||||
} else {
|
||||
$msgData = ['text' => $text];
|
||||
if ($markdown) {
|
||||
@@ -1630,6 +1647,18 @@ class DialogController extends AbstractController
|
||||
$msg = File::formatFileData($msg);
|
||||
$data['content'] = $msg['content'];
|
||||
$data['file_mode'] = $msg['file_mode'];
|
||||
} elseif ($data['type'] == 'longtext') {
|
||||
$data['content'] = [
|
||||
'type' => 'htm',
|
||||
'content' => Doo::translate("内容不存在")
|
||||
];
|
||||
if (isset($data['msg']['file']['path'])) {
|
||||
$filePath = public_path($data['msg']['file']['path']);
|
||||
if (file_exists($filePath)) {
|
||||
$data['content']['type'] = $data['msg']['type'];
|
||||
$data['content']['content'] = file_get_contents($filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('success', $data);
|
||||
@@ -1673,7 +1702,7 @@ class DialogController extends AbstractController
|
||||
}
|
||||
//
|
||||
$filePath = public_path($array['path']);
|
||||
return Base::BinaryFileResponse($filePath, $array['name']);
|
||||
return Base::DownloadFileResponse($filePath, $array['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -301,6 +301,7 @@ class FileController extends AbstractController
|
||||
//
|
||||
$userid = $user->userid;
|
||||
if ($row->pid > 0) {
|
||||
File::permissionFind($row->pid, $user, 1);
|
||||
$userid = intval(File::whereId($row->pid)->value('userid'));
|
||||
}
|
||||
//
|
||||
|
||||
@@ -1058,20 +1058,20 @@ class ProjectController extends AbstractController
|
||||
$query->where('project_users.owner', 1);
|
||||
$query->where('project_users.userid', $userid);
|
||||
});
|
||||
$builder->leftJoin('project_task_users as project_sub_task_users', function ($query) use($userid) {
|
||||
$query->on('project_sub_task_users.task_pid', '=', 'project_tasks.parent_id');
|
||||
$query->where('project_sub_task_users.userid', $userid);
|
||||
});
|
||||
$builder->leftJoin('project_task_visibility_users', function ($query) use($userid) {
|
||||
$query->on('project_task_visibility_users.task_id', '=', 'project_tasks.id');
|
||||
$query->where('project_task_visibility_users.userid', $userid);
|
||||
});
|
||||
$builder->leftJoin('project_task_visibility_users as project_sub_task_visibility_users', function ($query) use($userid) {
|
||||
$query->on('project_sub_task_visibility_users.task_id', '=', 'project_tasks.parent_id');
|
||||
$query->where('project_sub_task_visibility_users.userid', $userid);
|
||||
});
|
||||
$builder->where(function ($query) use ($userid) {
|
||||
$query->where("project_tasks.visibility", 1);
|
||||
$query->orWhere("project_users.userid", $userid);
|
||||
$query->orWhere("project_task_users.userid", $userid);
|
||||
$query->orWhere("project_task_visibility_users.userid", $userid);
|
||||
$query->orWhere("project_sub_task_users.userid", $userid);
|
||||
$query->orWhere("project_sub_task_visibility_users.userid", $userid);
|
||||
});
|
||||
// 优化子查询汇总
|
||||
$builder->leftJoinSub(function ($query) {
|
||||
@@ -1159,6 +1159,7 @@ class ProjectController extends AbstractController
|
||||
$list = ProjectTask::with(['taskUser'])
|
||||
->select([
|
||||
'projects.name as project_name',
|
||||
'project_tasks.project_id',
|
||||
'project_tasks.id',
|
||||
'project_tasks.name',
|
||||
'project_tasks.start_at',
|
||||
@@ -1852,7 +1853,7 @@ class ProjectController extends AbstractController
|
||||
}
|
||||
//
|
||||
$filePath = public_path($file->getRawOriginal('path'));
|
||||
return Base::BinaryFileResponse($filePath, $file->name);
|
||||
return Base::DownloadFileResponse($filePath, $file->name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2399,6 +2400,7 @@ class ProjectController extends AbstractController
|
||||
*/
|
||||
public function task__move()
|
||||
{
|
||||
Base::checkClientVersion('0.42.0');
|
||||
User::auth();
|
||||
//
|
||||
$task_id = intval(Request::input('task_id'));
|
||||
@@ -2436,9 +2438,26 @@ class ProjectController extends AbstractController
|
||||
//
|
||||
$task->moveTask($project_id, $column_id, $flow_item_id, $owner, $assist, $completeAt);
|
||||
//
|
||||
$task = ProjectTask::userTask($task_id);
|
||||
$data = [];
|
||||
$mainTask = ProjectTask::userTask($task_id)?->toArray();
|
||||
if ($mainTask) {
|
||||
$mainTask['column_name'] = ProjectColumn::whereId($mainTask['column_id'])->value('name');
|
||||
$mainTask['project_name'] = Project::whereId($mainTask['project_id'])->value('name');
|
||||
$data[] = $mainTask;
|
||||
//
|
||||
$subTasks = ProjectTask::whereParentId($task_id)->get();
|
||||
foreach ($subTasks as $subTask) {
|
||||
$data[] = [
|
||||
'id' => $subTask->id,
|
||||
'project_id' => $subTask->project_id,
|
||||
'column_id' => $subTask->column_id,
|
||||
'column_name' => $mainTask['column_name'],
|
||||
'project_name' => $mainTask['project_name'],
|
||||
];
|
||||
}
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('移动成功', $task);
|
||||
return Base::retSuccess('移动成功', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,7 +41,7 @@ class SystemController extends AbstractController
|
||||
* @apiParam {String} type
|
||||
* - get: 获取(默认)
|
||||
* - all: 获取所有(需要管理员权限)
|
||||
* - save: 保存设置(参数:['reg', 'reg_identity', 'reg_invite', 'temp_account_alias', 'login_code', 'password_policy', 'project_invite', 'chat_information', 'anon_message', 'voice2text', 'translation', 'e2e_message', 'auto_archived', 'archived_day', 'task_visible', 'task_default_time', 'all_group_mute', 'all_group_autoin', 'user_private_chat_mute', 'user_group_chat_mute', 'system_alias', 'image_compress', 'image_quality', 'image_save_local', 'start_home'])
|
||||
* - save: 保存设置(参数:['reg', 'reg_identity', 'reg_invite', 'temp_account_alias', 'login_code', 'password_policy', 'project_invite', 'chat_information', 'anon_message', 'voice2text', 'translation', 'e2e_message', 'auto_archived', 'archived_day', 'task_visible', 'task_default_time', 'all_group_mute', 'all_group_autoin', 'user_private_chat_mute', 'user_group_chat_mute', 'system_alias', 'system_welcome', 'image_compress', 'image_quality', 'image_save_local', 'start_home'])
|
||||
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@@ -80,6 +80,7 @@ class SystemController extends AbstractController
|
||||
'user_private_chat_mute',
|
||||
'user_group_chat_mute',
|
||||
'system_alias',
|
||||
'system_welcome',
|
||||
'image_compress',
|
||||
'image_quality',
|
||||
'image_save_local',
|
||||
@@ -108,6 +109,9 @@ class SystemController extends AbstractController
|
||||
if ($all['system_alias'] == env('APP_NAME')) {
|
||||
$all['system_alias'] = '';
|
||||
}
|
||||
if ($all['system_welcome'] == '欢迎您,{username}') {
|
||||
$all['system_welcome'] = '';
|
||||
}
|
||||
$setting = Base::setting('system', Base::newTrim($all));
|
||||
} else {
|
||||
$setting = Base::setting('system');
|
||||
|
||||
@@ -1151,6 +1151,9 @@ class UsersController extends AbstractController
|
||||
* - update: 更新(默认)
|
||||
* - remove: 删除
|
||||
* @apiParam {String} alias 别名
|
||||
* @apiParam {String} [userAgent] 浏览器信息
|
||||
* @apiParam {String} [deviceModel] 设备型号
|
||||
* @apiParam {String} [isNotified] 是否有通知权限(0不通知、1通知)
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@@ -1182,11 +1185,15 @@ class UsersController extends AbstractController
|
||||
'alias' => $data['alias'],
|
||||
'platform' => Base::platform(),
|
||||
];
|
||||
$version = $data['appVersion'] ? ($data['appVersionName'] . " ({$data['appVersion']})") : '';
|
||||
$isNotified = trim($data['isNotified']) === 'true' || $data['isNotified'] === true ? 1 : intval($data['isNotified']);
|
||||
$row = UmengAlias::where($inArray);
|
||||
if ($row->exists()) {
|
||||
$row->update([
|
||||
'ua' => $data['userAgent'],
|
||||
'device' => $data['deviceModel'],
|
||||
'version' => $version,
|
||||
'is_notified' => $isNotified,
|
||||
'updated_at' => Carbon::now()
|
||||
]);
|
||||
return Base::retSuccess('别名已存在');
|
||||
@@ -1194,6 +1201,8 @@ class UsersController extends AbstractController
|
||||
$row = UmengAlias::createInstance(array_merge($inArray, [
|
||||
'ua' => $data['userAgent'],
|
||||
'device' => $data['deviceModel'],
|
||||
'version' => $version,
|
||||
'is_notified' => $isNotified,
|
||||
]));
|
||||
if ($row->save()) {
|
||||
return Base::retSuccess('添加成功');
|
||||
|
||||
@@ -210,8 +210,8 @@ class AbstractModel extends Model
|
||||
/**
|
||||
* 数据库更新或插入
|
||||
* @param $where
|
||||
* @param array $update 存在时更新的内容
|
||||
* @param array $insert 不存在时插入的内容,如果没有则插入更新内容
|
||||
* @param array|\Closure $update 存在时更新的内容
|
||||
* @param array|\Closure $insert 不存在时插入的内容,如果没有则插入更新内容
|
||||
* @param bool $isInsert 是否是插入数据
|
||||
* @return AbstractModel|\Illuminate\Database\Eloquent\Builder|Model|object|static|null
|
||||
*/
|
||||
@@ -220,6 +220,12 @@ class AbstractModel extends Model
|
||||
$row = static::where($where)->first();
|
||||
if (empty($row)) {
|
||||
$row = new static;
|
||||
if ($update instanceof \Closure) {
|
||||
$update = $update();
|
||||
}
|
||||
if ($insert instanceof \Closure) {
|
||||
$insert = $insert();
|
||||
}
|
||||
$array = array_merge($where, $insert ?: $update);
|
||||
if (isset($array[$row->primaryKey])) {
|
||||
unset($array[$row->primaryKey]);
|
||||
@@ -227,6 +233,9 @@ class AbstractModel extends Model
|
||||
$row->updateInstance($array);
|
||||
$isInsert = true;
|
||||
} elseif ($update) {
|
||||
if ($update instanceof \Closure) {
|
||||
$update = $update();
|
||||
}
|
||||
$row->updateInstance($update);
|
||||
$isInsert = false;
|
||||
}
|
||||
|
||||
45
app/Models/ApproveProcInstHistory.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Cache;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
|
||||
class ApproveProcInstHistory extends AbstractModel
|
||||
{
|
||||
protected $table = 'approve_proc_inst_history';
|
||||
|
||||
/**
|
||||
* 获取用户审批状态(请假、外出)
|
||||
* @param $userid
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function getUserApprovalStatus($userid)
|
||||
{
|
||||
if (empty($userid)) {
|
||||
return null;
|
||||
}
|
||||
return Cache::remember('user_is_leave_' . $userid, Carbon::now()->addMinute(), function () use ($userid) {
|
||||
return self::where([
|
||||
['start_user_id', '=', $userid],
|
||||
[DB::raw("JSON_UNQUOTE(JSON_EXTRACT(var, '$.startTime'))"), '<=', Carbon::now()->toDateTimeString()],
|
||||
[DB::raw("JSON_UNQUOTE(JSON_EXTRACT(var, '$.endTime'))"), '>=', Carbon::now()->toDateTimeString()],
|
||||
['state', '=', 2]
|
||||
])->where(function ($query) {
|
||||
$query->where('proc_def_name', 'like', '%请假%')
|
||||
->orWhere('proc_def_name', 'like', '%外出%');
|
||||
})->orderByDesc('id')->value('proc_def_name');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断用户是否请假(包含:请假、外出)
|
||||
* @param $userid
|
||||
* @return bool
|
||||
*/
|
||||
public static function userIsLeave($userid)
|
||||
{
|
||||
return (bool)self::getUserApprovalStatus($userid);
|
||||
}
|
||||
}
|
||||
@@ -79,9 +79,28 @@ class File extends AbstractModel
|
||||
* office文件
|
||||
*/
|
||||
const officeExt = [
|
||||
'doc', 'docx',
|
||||
'xls', 'xlsx',
|
||||
'ppt', 'pptx',
|
||||
// 文本文件
|
||||
'doc', 'docx', // Microsoft Word 文档
|
||||
'dot', 'dotx', // Word 模板
|
||||
'odt', // OpenDocument 文本格式
|
||||
'ott', // OpenDocument 文本模板
|
||||
'rtf', // 富文本格式
|
||||
|
||||
// 电子表格
|
||||
'xls', 'xlsx', // Microsoft Excel 电子表格
|
||||
'xlsm', // Excel 含宏的工作簿
|
||||
'xlt', 'xltx', // Excel 模板
|
||||
'ods', // OpenDocument 电子表格格式
|
||||
'ots', // OpenDocument 电子表格模板
|
||||
'csv', // 逗号分隔值
|
||||
'tsv', // 制表符分隔值
|
||||
|
||||
// 演示文稿
|
||||
'ppt', 'pptx', // Microsoft PowerPoint 演示文稿
|
||||
'pps', 'ppsx', // PowerPoint 幻灯片放映
|
||||
'pot', 'potx', // PowerPoint 模板
|
||||
'odp', // OpenDocument 演示文稿格式
|
||||
'otp', // OpenDocument 演示文稿模板
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -264,9 +283,9 @@ class File extends AbstractModel
|
||||
'text', 'md', 'markdown' => 'document',
|
||||
'drawio' => 'drawio',
|
||||
'mind' => 'mind',
|
||||
'doc', 'docx' => "word",
|
||||
'xls', 'xlsx' => "excel",
|
||||
'ppt', 'pptx' => "ppt",
|
||||
'doc', 'docx', 'dot', 'dotx', 'odt', 'ott', 'rtf' => "word",
|
||||
'xls', 'xlsx', 'xlsm', 'xlt', 'xltx', 'ods', 'ots', 'csv', 'tsv' => "excel",
|
||||
'ppt', 'pptx', 'pps', 'ppsx', 'pot', 'potx', 'odp', 'otp' => "ppt",
|
||||
'wps' => "wps",
|
||||
'jpg', 'jpeg', 'webp', 'png', 'gif', 'bmp', 'ico', 'raw', 'svg' => "picture",
|
||||
'rar', 'zip', 'jar', '7-zip', 'tar', 'gzip', '7z', 'gz', 'apk', 'dmg' => "archive",
|
||||
@@ -706,9 +725,9 @@ class File extends AbstractModel
|
||||
* @param int $permission
|
||||
* @return File
|
||||
*/
|
||||
public static function permissionFind(int $id, $user, int $limit = 0, int &$permission = -1)
|
||||
public static function permissionFind($id, $user, int $limit = 0, int &$permission = -1)
|
||||
{
|
||||
$file = File::find($id);
|
||||
$file = File::find(intval($id));
|
||||
if (empty($file)) {
|
||||
throw new ApiException('文件不存在或已被删除');
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace App\Models;
|
||||
use App\Module\Base;
|
||||
use App\Module\Timer;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
|
||||
/**
|
||||
* App\Models\FileContent
|
||||
@@ -104,10 +105,10 @@ class FileContent extends AbstractModel
|
||||
|
||||
/**
|
||||
* 获取格式内容(或下载)
|
||||
* @param File $file
|
||||
* @param $file
|
||||
* @param $content
|
||||
* @param $download
|
||||
* @return array|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
* @return array|StreamedResponse
|
||||
*/
|
||||
public static function formatContent($file, $content, $download = false)
|
||||
{
|
||||
@@ -119,7 +120,7 @@ class FileContent extends AbstractModel
|
||||
} else {
|
||||
$filePath = public_path($content['url']);
|
||||
}
|
||||
return Base::BinaryFileResponse($filePath, $name);
|
||||
return Base::DownloadFileResponse($filePath, $name);
|
||||
}
|
||||
if (empty($content)) {
|
||||
$content = match ($file->type) {
|
||||
@@ -148,7 +149,7 @@ class FileContent extends AbstractModel
|
||||
if ($download) {
|
||||
$filePath = public_path($path);
|
||||
if (isset($filePath)) {
|
||||
return Base::BinaryFileResponse($filePath, $name);
|
||||
return Base::DownloadFileResponse($filePath, $name);
|
||||
} else {
|
||||
abort(403, "This file not support download.");
|
||||
}
|
||||
|
||||
@@ -219,7 +219,11 @@ class Project extends AbstractModel
|
||||
'userid' => $userid,
|
||||
], [
|
||||
'important' => 1
|
||||
]);
|
||||
], function () use ($userid) {
|
||||
return [
|
||||
'bot' => User::isBot($userid) ? 1 : 0,
|
||||
];
|
||||
});
|
||||
}
|
||||
WebSocketDialogUser::whereDialogId($this->dialog_id)->whereNotIn('userid', $userids)->whereImportant(1)->remove();
|
||||
});
|
||||
|
||||
@@ -1180,7 +1180,11 @@ class ProjectTask extends AbstractModel
|
||||
'userid' => $userid,
|
||||
], [
|
||||
'important' => 1
|
||||
]);
|
||||
], function () use ($userid) {
|
||||
return [
|
||||
'bot' => User::isBot($userid) ? 1 : 0,
|
||||
];
|
||||
});
|
||||
}
|
||||
WebSocketDialogUser::whereDialogId($this->dialog_id)->whereNotIn('userid', $userids)->whereImportant(1)->remove();
|
||||
});
|
||||
@@ -1833,6 +1837,11 @@ class ProjectTask extends AbstractModel
|
||||
$taskUser->save();
|
||||
}
|
||||
}
|
||||
// 子任务
|
||||
ProjectTask::whereParentId($this->id)->change([
|
||||
'project_id' => $projectId,
|
||||
'column_id' => $columnId,
|
||||
]);
|
||||
//
|
||||
if ($flowItemId) {
|
||||
$flowItem = projectFlowItem::whereProjectId($projectId)->whereId($flowItemId)->first();
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Module\Base;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectUser
|
||||
*
|
||||
@@ -50,7 +52,9 @@ class ProjectUser extends AbstractModel
|
||||
*/
|
||||
public static function transfer($originalUserid, $newUserid)
|
||||
{
|
||||
self::whereUserid($originalUserid)->chunkById(100, function ($list) use ($originalUserid, $newUserid) {
|
||||
$projectIds = [];
|
||||
// 移交项目身份
|
||||
self::whereUserid($originalUserid)->chunkById(100, function ($list) use ($originalUserid, $newUserid, &$projectIds) {
|
||||
/** @var self $item */
|
||||
foreach ($list as $item) {
|
||||
$row = self::whereProjectId($item->project_id)->whereUserid($newUserid)->first();
|
||||
@@ -72,9 +76,23 @@ class ProjectUser extends AbstractModel
|
||||
}
|
||||
$item->project->addLog("移交项目身份", ['userid' => [$originalUserid, ' => ', $newUserid]]);
|
||||
$item->project->syncDialogUser();
|
||||
$projectIds[] = $item->project_id;
|
||||
}
|
||||
}
|
||||
});
|
||||
// 移交工作流状态负责人
|
||||
if ($projectIds) {
|
||||
ProjectFlowItem::whereIn('project_id', $projectIds)->chunkById(100, function ($list) use ($originalUserid, $newUserid) {
|
||||
/** @var ProjectFlowItem $item */
|
||||
foreach ($list as $item) {
|
||||
if (in_array($originalUserid, $item->userids)) {
|
||||
$userids = array_values(array_diff($item->userids, [$originalUserid]));
|
||||
$item->userids = Base::array2json(array_merge($userids, [$newUserid]));
|
||||
$item->save();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,12 @@ class Report extends AbstractModel
|
||||
// 如果设置了周期偏移量
|
||||
empty( $offset ) || $now_dt->subWeeks( abs( $offset ) );
|
||||
$now_dt->startOfWeek(); // 设置为当周第一天
|
||||
return $now_dt->year . $now_dt->weekOfYear;
|
||||
return now()->year . $now_dt->weekOfYear;
|
||||
},
|
||||
Report::DAILY => function() use ($now_dt, $offset) {
|
||||
// 如果设置了周期偏移量
|
||||
empty( $offset ) || $now_dt->subDays( abs( $offset ) );
|
||||
return $now_dt->format("Ymd");
|
||||
return now()->format("Ymd");
|
||||
},
|
||||
default => "",
|
||||
};
|
||||
|
||||
@@ -65,14 +65,15 @@ class Setting extends AbstractModel
|
||||
$value['claude_key'] = $value['claude_token'];
|
||||
}
|
||||
$array = [];
|
||||
$aiList = ['openai', 'claude', 'gemini', 'zhipu', 'qianwen', 'wenxin'];
|
||||
$fieldList = ['key', 'model', 'agency', 'system', 'secret'];
|
||||
$aiList = ['openai', 'claude', 'deepseek', 'gemini', 'zhipu', 'qianwen', 'wenxin'];
|
||||
$fieldList = ['key', 'model', 'base_url', 'agency', 'system', 'secret'];
|
||||
foreach ($aiList as $aiName) {
|
||||
foreach ($fieldList as $fieldName) {
|
||||
$key = $aiName . '_' . $fieldName;
|
||||
$array[$key] = $value[$key] ?: match ($key) {
|
||||
'openai_model' => 'gpt-4o-mini',
|
||||
'claude_model' => 'claude-3-5-sonnet-latest',
|
||||
'deepseek_model' => 'deepseek-chat',
|
||||
'gemini_model' => 'gemini-1.5-flash',
|
||||
'zhipu_model' => 'glm-4',
|
||||
'qianwen_model' => 'qwen-turbo',
|
||||
|
||||
@@ -15,7 +15,9 @@ use Hedeqiang\UMeng\IOS;
|
||||
* @property string|null $alias 别名
|
||||
* @property string|null $platform 平台类型
|
||||
* @property string|null $device 设备类型
|
||||
* @property string|null $version 应用版本号
|
||||
* @property string|null $ua userAgent
|
||||
* @property int|null $is_notified 通知权限
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
@@ -30,7 +32,9 @@ use Hedeqiang\UMeng\IOS;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias whereAlias($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias whereDevice($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias whereVersion($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias whereIsNotified($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias wherePlatform($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias whereUa($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias whereUpdatedAt($value)
|
||||
@@ -189,7 +193,11 @@ class UmengAlias extends AbstractModel
|
||||
$lists = $rows->take(5)->groupBy('platform'); // 每个会员最多推送5个别名
|
||||
foreach ($lists as $platform => $list) {
|
||||
$alias = $list->pluck('alias')->implode(',');
|
||||
self::pushMsgToAlias($alias, $platform, $array);
|
||||
try {
|
||||
self::pushMsgToAlias($alias, $platform, $array);
|
||||
} catch (\Exception $e) {
|
||||
info("[PushMsg] fail: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -593,6 +593,8 @@ class User extends AbstractModel
|
||||
return url("images/avatar/default_openai.png");
|
||||
case 'ai-claude@bot.system':
|
||||
return url("images/avatar/default_claude.png");
|
||||
case 'ai-deepseek@bot.system':
|
||||
return url("images/avatar/default_deepseek.png");
|
||||
case 'ai-gemini@bot.system':
|
||||
return url("images/avatar/default_gemini.png");
|
||||
case 'ai-zhipu@bot.system':
|
||||
|
||||
@@ -83,6 +83,7 @@ class UserBot extends AbstractModel
|
||||
'approval-alert' => '审批',
|
||||
'ai-openai' => 'ChatGPT',
|
||||
'ai-claude' => 'Claude',
|
||||
'ai-deepseek' => 'DeepSeek',
|
||||
'ai-wenxin' => '文心一言',
|
||||
'ai-qianwen' => '通义千问',
|
||||
'ai-gemini' => 'Gemini',
|
||||
|
||||
@@ -265,7 +265,9 @@ class WebSocketDialog extends AbstractModel
|
||||
// 未读消息
|
||||
$data = array_merge($data, self::generateUnread($data['id'], $userid));
|
||||
// 对话人数
|
||||
$data['people'] = $data['people'] ?? WebSocketDialogUser::whereDialogId($data['id'])->count();
|
||||
if (!isset($data['people'])) {
|
||||
$data = array_merge($data, self::generatePeople($data['id']));
|
||||
}
|
||||
// 有待办
|
||||
$data['todo_num'] = $data['todo_num'] ?? WebSocketDialogMsgTodo::whereDialogId($data['id'])->whereUserid($userid)->whereDoneAt(null)->count();
|
||||
// 最后消息
|
||||
@@ -330,6 +332,9 @@ class WebSocketDialog extends AbstractModel
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (empty($data['pinyin'])) {
|
||||
$data['pinyin'] = Base::cn2pinyin($data['name']);
|
||||
}
|
||||
|
||||
// 已存在的消息类型
|
||||
if ($hasData === true) {
|
||||
@@ -398,6 +403,26 @@ class WebSocketDialog extends AbstractModel
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对话人数
|
||||
* @param $dialogId
|
||||
* @return array
|
||||
*/
|
||||
public static function generatePeople($dialogId)
|
||||
{
|
||||
$counts = WebSocketDialogUser::whereDialogId($dialogId)
|
||||
->groupBy('bot')
|
||||
->selectRaw('bot, COUNT(*) as count')
|
||||
->pluck('count', 'bot');
|
||||
$userCount = $counts->get(0, 0); // 非机器人数量
|
||||
$botCount = $counts->get(1, 0); // 机器人数量
|
||||
return [
|
||||
'people' => $userCount + $botCount,
|
||||
'people_user' => $userCount,
|
||||
'people_bot' => $botCount,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入聊天室
|
||||
* @param int|array $userid 加入的会员ID或会员ID组
|
||||
@@ -420,7 +445,11 @@ class WebSocketDialog extends AbstractModel
|
||||
WebSocketDialogUser::updateInsert([
|
||||
'dialog_id' => $this->id,
|
||||
'userid' => $value,
|
||||
], $updateData, [], $isInsert);
|
||||
], $updateData, function() use ($value) {
|
||||
return [
|
||||
'bot' => User::isBot($value) ? 1 : 0,
|
||||
];
|
||||
}, $isInsert);
|
||||
if ($isInsert) {
|
||||
WebSocketDialogMsg::sendMsg(null, $this->id, 'notice', [
|
||||
'notice' => User::userid2nickname($value) . " 已加入群组"
|
||||
@@ -429,10 +458,9 @@ class WebSocketDialog extends AbstractModel
|
||||
}
|
||||
}
|
||||
});
|
||||
$this->pushMsg("groupUpdate", [
|
||||
'id' => $this->id,
|
||||
'people' => WebSocketDialogUser::whereDialogId($this->id)->count()
|
||||
]);
|
||||
$data = WebSocketDialog::generatePeople($this->id);
|
||||
$data['id'] = $this->id;
|
||||
$this->pushMsg("groupUpdate", $data);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -489,10 +517,9 @@ class WebSocketDialog extends AbstractModel
|
||||
});
|
||||
});
|
||||
//
|
||||
$this->pushMsg("groupUpdate", [
|
||||
'id' => $this->id,
|
||||
'people' => WebSocketDialogUser::whereDialogId($this->id)->count()
|
||||
]);
|
||||
$data = WebSocketDialog::generatePeople($this->id);
|
||||
$data['id'] = $this->id;
|
||||
$this->pushMsg("groupUpdate", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -592,6 +592,9 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
case 'text':
|
||||
return self::previewTextMsg($data['msg'], $preserveHtml);
|
||||
|
||||
case 'longtext':
|
||||
return $data['msg']['desc'] ? Base::cutStr($data['msg']['desc'], 50) : ("[" . Doo::translate("长文本") . "]");
|
||||
|
||||
case 'vote':
|
||||
$action = Doo::translate("投票");
|
||||
return "[{$action}] " . self::previewTextMsg($data['msg'], $preserveHtml);
|
||||
@@ -774,14 +777,24 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
break;
|
||||
}
|
||||
}
|
||||
$key = str_replace([""", "&", "<", ">"], "", $key);
|
||||
$key = str_replace(["\r", "\n", "\t", " "], " ", $key);
|
||||
$key = preg_replace("/^\/[A-Za-z]+/", " ", $key);
|
||||
$key = preg_replace("/\s+/", " ", $key);
|
||||
$this->key = trim($key);
|
||||
$this->key = self::filterEscape($key);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤转义
|
||||
* @param $content
|
||||
* @return string
|
||||
*/
|
||||
public static function filterEscape($content)
|
||||
{
|
||||
$content = str_replace([""", "&", "<", ">"], "", $content);
|
||||
$content = str_replace(["\r", "\n", "\t", " "], " ", $content);
|
||||
$content = preg_replace("/^\/[A-Za-z]+/", " ", $content);
|
||||
$content = preg_replace("/\s+/", " ", $content);
|
||||
return trim($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回引用消息(如果是文本只取预览)
|
||||
* @return array|mixed
|
||||
|
||||
@@ -14,6 +14,7 @@ use Overtrue\Pinyin\Pinyin;
|
||||
use Redirect;
|
||||
use Request;
|
||||
use Storage;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
use Validator;
|
||||
@@ -2017,7 +2018,7 @@ class Base
|
||||
$type = ['mp3', 'wma', 'wav', 'amr'];
|
||||
break;
|
||||
case 'excel':
|
||||
$type = ['xls', 'xlsx'];
|
||||
$type = ['xls', 'xlsx', 'xlsm', 'xlt', 'xltx', 'ods', 'ots', 'csv', 'tsv'];
|
||||
break;
|
||||
case 'app':
|
||||
$type = ['apk'];
|
||||
@@ -2758,12 +2759,12 @@ class Base
|
||||
}
|
||||
|
||||
/**
|
||||
* BinaryFileResponse 下载文件
|
||||
* DownloadFileResponse 下载文件
|
||||
* @param File|\SplFileInfo|string $file 文件对象或路径
|
||||
* @param string|null $name 下载文件名
|
||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
* @return StreamedResponse
|
||||
*/
|
||||
public static function BinaryFileResponse($file, $name = null)
|
||||
public static function DownloadFileResponse($file, $name = null)
|
||||
{
|
||||
try {
|
||||
// 处理文件对象
|
||||
@@ -2780,6 +2781,12 @@ class Base
|
||||
throw new FileException('File must be readable and exist.');
|
||||
}
|
||||
|
||||
// 获取文件信息
|
||||
$size = $file->getSize();
|
||||
if ($size === false || $size < 0) {
|
||||
throw new FileException('Unable to determine file size.');
|
||||
}
|
||||
|
||||
// 处理文件名
|
||||
if (empty($name)) {
|
||||
$name = basename($file->getPathname());
|
||||
@@ -2791,34 +2798,98 @@ class Base
|
||||
$name = Base::cutStr($name, 180);
|
||||
$name = str_replace(['"', '<', '>', '|', '/', '\\', '?', ':'], '', $name);
|
||||
|
||||
// IE 浏览器特殊处理
|
||||
$encodedName = $name;
|
||||
if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/MSIE|Internet Explorer|Trident/i", $_SERVER['HTTP_USER_AGENT'])) {
|
||||
$encodedName = rawurlencode($name);
|
||||
// 获取MIME类型
|
||||
$mimeType = $file->getMimeType();
|
||||
if (empty($mimeType)) {
|
||||
$mimeType = 'application/octet-stream';
|
||||
}
|
||||
|
||||
// 创建响应对象
|
||||
return new \Symfony\Component\HttpFoundation\BinaryFileResponse($file->getPathname(), 200, [
|
||||
'Content-Type' => $file->getMimeType() ?: 'application/octet-stream',
|
||||
// 处理 Range 请求
|
||||
$start = 0;
|
||||
$end = $size - 1;
|
||||
$length = $size;
|
||||
$isRangeRequest = false;
|
||||
|
||||
if (isset($_SERVER['HTTP_RANGE'])) {
|
||||
$range = str_replace('bytes=', '', $_SERVER['HTTP_RANGE']);
|
||||
if (preg_match('/^(\d+)-(\d*)$/', $range, $matches)) {
|
||||
$start = intval($matches[1]);
|
||||
$end = !empty($matches[2]) ? intval($matches[2]) : $size - 1;
|
||||
|
||||
// 验证范围的有效性
|
||||
if ($start >= 0 && $end < $size && $start <= $end) {
|
||||
$length = $end - $start + 1;
|
||||
$isRangeRequest = true;
|
||||
} else {
|
||||
$start = 0;
|
||||
$end = $size - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 设置基本响应头
|
||||
$headers = [
|
||||
'Content-Type' => $mimeType,
|
||||
'Content-Disposition' => sprintf(
|
||||
'attachment; filename="%s"; filename*=UTF-8\'\'%s',
|
||||
$encodedName,
|
||||
$name,
|
||||
rawurlencode($name)
|
||||
),
|
||||
// 添加缓存控制和安全相关的头
|
||||
'Cache-Control' => 'private, no-transform, no-store, must-revalidate',
|
||||
'Pragma' => 'public',
|
||||
'Expires' => '0',
|
||||
'Accept-Ranges' => 'bytes', // 支持断点续传
|
||||
'X-Content-Type-Options' => 'nosniff', // 安全相关
|
||||
]);
|
||||
'Accept-Ranges' => 'bytes',
|
||||
'Cache-Control' => 'private, no-transform, no-store, must-revalidate, max-age=0',
|
||||
'Content-Length' => $length,
|
||||
'Last-Modified' => gmdate('D, d M Y H:i:s', $file->getMTime()) . ' GMT',
|
||||
'ETag' => sprintf('"%s"', md5_file($file->getPathname()))
|
||||
];
|
||||
|
||||
if ($isRangeRequest) {
|
||||
$headers['Content-Range'] = "bytes {$start}-{$end}/{$size}";
|
||||
$statusCode = 206;
|
||||
} else {
|
||||
$statusCode = 200;
|
||||
}
|
||||
|
||||
// 创建流式响应
|
||||
return new StreamedResponse(
|
||||
function () use ($file, $start, $length) {
|
||||
$handle = fopen($file->getPathname(), 'rb');
|
||||
if ($handle === false) {
|
||||
throw new FileException('Cannot open file for reading');
|
||||
}
|
||||
|
||||
if (fseek($handle, $start) === -1) {
|
||||
fclose($handle);
|
||||
throw new FileException('Cannot seek to position ' . $start);
|
||||
}
|
||||
|
||||
$remaining = $length;
|
||||
$bufferSize = 8192; // 8KB chunks
|
||||
|
||||
while ($remaining > 0 && !feof($handle)) {
|
||||
$readSize = min($bufferSize, $remaining);
|
||||
$buffer = fread($handle, $readSize);
|
||||
if ($buffer === false) {
|
||||
break;
|
||||
}
|
||||
echo $buffer;
|
||||
flush();
|
||||
$remaining -= strlen($buffer);
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
},
|
||||
$statusCode,
|
||||
$headers
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('File download failed', [
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
'file' => $file->getPathname() ?? null,
|
||||
'name' => $name ?? null,
|
||||
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null, // 添加更多调试信息
|
||||
'ip' => request()->ip()
|
||||
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
|
||||
'ip' => request()->ip(),
|
||||
'range' => $_SERVER['HTTP_RANGE'] ?? null
|
||||
]);
|
||||
abort(403, 'File download failed');
|
||||
}
|
||||
|
||||
108
app/Module/MsgTool.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Module;
|
||||
|
||||
|
||||
use DOMDocument;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use League\CommonMark\Exception\CommonMarkException;
|
||||
use League\HTMLToMarkdown\HtmlConverter;
|
||||
|
||||
class MsgTool
|
||||
{
|
||||
/**
|
||||
* 截取文本并保持标签完整性
|
||||
*
|
||||
* @param string $text 要截取的文本
|
||||
* @param int $length 截取长度
|
||||
* @param string $type 文本类型 (htm 或 md)
|
||||
* @return string 处理后的文本
|
||||
*/
|
||||
public static function truncateText($text, $length, $type = 'htm')
|
||||
{
|
||||
if (empty($text) || mb_strlen($text) <= $length) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
$isMd = strtolower($type) === 'md';
|
||||
|
||||
// 如果是Markdown,转换为HTML
|
||||
if ($isMd) {
|
||||
$converter = new CommonMarkConverter();
|
||||
try {
|
||||
$text = $converter->convert($text);
|
||||
} catch (CommonMarkException) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
// 创建DOM文档
|
||||
$dom = new DOMDocument('1.0', 'UTF-8');
|
||||
libxml_use_internal_errors(true);
|
||||
$dom->loadHTML(mb_convert_encoding($text, 'HTML-ENTITIES', 'UTF-8'));
|
||||
libxml_clear_errors();
|
||||
|
||||
// 获取body元素
|
||||
$body = $dom->getElementsByTagName('body')->item(0);
|
||||
$truncatedHtml = '';
|
||||
$currentLength = 0;
|
||||
|
||||
// 递归函数来遍历节点并截取内容
|
||||
self::traverseNodes($body, $currentLength, $length, $truncatedHtml);
|
||||
|
||||
// 如果是Markdown,转换回Markdown
|
||||
if ($isMd) {
|
||||
$converter = new HtmlConverter();
|
||||
$truncatedHtml = $converter->convert($truncatedHtml);
|
||||
}
|
||||
|
||||
return $truncatedHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归遍历节点
|
||||
* @param $node
|
||||
* @param $currentLength
|
||||
* @param $length
|
||||
* @param $truncatedHtml
|
||||
* @return void
|
||||
*/
|
||||
private static function traverseNodes($node, &$currentLength, $length, &$truncatedHtml)
|
||||
{
|
||||
foreach ($node->childNodes as $child) {
|
||||
if ($currentLength >= $length) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($child->nodeType === XML_TEXT_NODE) {
|
||||
$textContent = $child->textContent;
|
||||
$remainingLength = $length - $currentLength;
|
||||
|
||||
if (mb_strlen($textContent) > $remainingLength) {
|
||||
$truncatedHtml .= htmlspecialchars(mb_substr($textContent, 0, $remainingLength) . '...');
|
||||
$currentLength += $remainingLength;
|
||||
} else {
|
||||
$truncatedHtml .= htmlspecialchars($textContent);
|
||||
$currentLength += mb_strlen($textContent);
|
||||
}
|
||||
} elseif ($child->nodeType === XML_ELEMENT_NODE) {
|
||||
$truncatedHtml .= '<' . $child->nodeName;
|
||||
|
||||
// 添加属性
|
||||
if ($child->hasAttributes()) {
|
||||
foreach ($child->attributes as $attr) {
|
||||
$truncatedHtml .= ' ' . $attr->nodeName . '="' . htmlspecialchars($attr->nodeValue) . '"';
|
||||
}
|
||||
}
|
||||
|
||||
$truncatedHtml .= '>';
|
||||
|
||||
self::traverseNodes($child, $currentLength, $length, $truncatedHtml);
|
||||
|
||||
if ($currentLength < $length || $child->firstChild) {
|
||||
$truncatedHtml .= '</' . $child->nodeName . '>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,7 +92,7 @@ class ProjectTaskObserver
|
||||
}
|
||||
$array = [];
|
||||
if (in_array('task', $dataType)) {
|
||||
$array = array_merge($array, ProjectTaskUser::whereTaskId($projectTask->id)->pluck('userid')->toArray());
|
||||
$array = array_merge($array, ProjectTaskUser::whereTaskId($projectTask->id)->orWhere('task_pid' ,$projectTask->id)->pluck('userid')->toArray());
|
||||
}
|
||||
if (in_array('visibility', $dataType)) {
|
||||
$array = array_merge($array, ProjectTaskVisibilityUser::whereTaskId($projectTask->id)->pluck('userid')->toArray());
|
||||
@@ -121,5 +121,6 @@ class ProjectTaskObserver
|
||||
Deleted::forget('projectTask', $projectTask->id, $forgetUserids);
|
||||
break;
|
||||
}
|
||||
ProjectTask::whereParentId($projectTask->id)->change(['visibility' => $projectTask->visibility]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ class ProjectTaskUserObserver
|
||||
public function created(ProjectTaskUser $projectTaskUser)
|
||||
{
|
||||
Deleted::forget('projectTask', $projectTaskUser->task_id, $projectTaskUser->userid);
|
||||
if ($projectTaskUser->task_pid) {
|
||||
Deleted::forget('projectTask', $projectTaskUser->task_pid, $projectTaskUser->userid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -103,6 +103,10 @@ class WebSocketService implements WebSocketHandlerInterface
|
||||
case 'receipt':
|
||||
return;
|
||||
|
||||
// 握手信息
|
||||
case 'handshake':
|
||||
break;
|
||||
|
||||
// 访问状态
|
||||
case 'path':
|
||||
$row = WebSocket::whereFd($frame->fd)->first();
|
||||
|
||||
@@ -427,6 +427,7 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
'model_name' => $setting[$type . '_model'],
|
||||
'system_message' => $setting[$type . '_system'],
|
||||
'api_key' => $setting[$type . '_key'],
|
||||
'base_url' => $setting[$type . '_base_url'],
|
||||
'agency' => $setting[$type . '_agency'],
|
||||
'server_url' => $serverUrl,
|
||||
];
|
||||
@@ -445,7 +446,7 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
if ($replyMsg) {
|
||||
$replyCommand = $this->extractCommand($replyMsg);
|
||||
if ($replyCommand) {
|
||||
$replyCommand = Base::cutStr($replyCommand, 200) . "\n\n ------------------ Reference above ------------------ \n\n";
|
||||
$replyCommand = "<quoted>" . Base::cutStr($replyCommand, 2000) . "</quoted>\n\nThe content within the above <quoted> tags is a citation.\n\n";
|
||||
}
|
||||
}
|
||||
$command = $replyCommand . $command;
|
||||
@@ -585,14 +586,19 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
case 'user':
|
||||
break;
|
||||
case 'project':
|
||||
$projectInfo = Project::select(['id', 'name', 'archived_at', 'deleted_at'])->whereDialogId($dialog->id)->first();
|
||||
$projectInfo = Project::whereDialogId($dialog->id)->first();
|
||||
if ($projectInfo) {
|
||||
$before_text[] = "当前我在项目【{$projectInfo->name}】中";
|
||||
$projectText = "当前我在项目【{$projectInfo->name}】中";
|
||||
if ($projectInfo->archived_at) {
|
||||
$projectText .= ",此项目已经归档";
|
||||
}
|
||||
$before_text[] = $projectText;
|
||||
if ($projectInfo->desc) {
|
||||
$before_text[] = "项目描述:{$projectInfo->desc}";
|
||||
}
|
||||
$before_text[] = <<<EOF
|
||||
如果你判断我想要添加任务,请将任务标题和描述添加到回复中,例如:
|
||||
如果你判断我想要添加任务,请按照以下格式回复:
|
||||
|
||||
::: create-task-list
|
||||
title: 任务标题1
|
||||
desc: 任务描述1
|
||||
@@ -604,9 +610,17 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
}
|
||||
break;
|
||||
case 'task':
|
||||
$taskInfo = ProjectTask::with(['content'])->select(['id', 'name', 'complete_at', 'archived_at', 'deleted_at'])->whereDialogId($dialog->id)->first();
|
||||
$taskInfo = ProjectTask::with(['content'])->whereDialogId($dialog->id)->first();
|
||||
if ($taskInfo) {
|
||||
$before_text[] = "当前我在任务【{$taskInfo->name}】中";
|
||||
$taskText = "当前我在任务【{$taskInfo->name}】中";
|
||||
if ($taskInfo->archived_at) {
|
||||
$taskText .= ",此任务已经归档";
|
||||
} elseif ($taskInfo->complete_at) {
|
||||
$taskText .= ",此任务已经完成";
|
||||
} elseif ($taskInfo->end_at && Carbon::parse($taskInfo->end_at)->lt(Carbon::now())) {
|
||||
$taskText .= ",此任务已经过期";
|
||||
}
|
||||
$before_text[] = $taskText;
|
||||
if ($taskInfo->content) {
|
||||
$taskDesc = $taskInfo->content?->getContentInfo();
|
||||
if ($taskDesc) {
|
||||
@@ -620,8 +634,27 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
EOF;
|
||||
}
|
||||
}
|
||||
$subTask = ProjectTask::select(['id', 'name', 'complete_at', 'end_at'])->whereParentId($taskInfo->id)->get();
|
||||
if ($subTask->isNotEmpty()) {
|
||||
$subTaskContent = $subTask->map(function($item) {
|
||||
$status = "";
|
||||
if ($item->complete_at) {
|
||||
$status = " (已完成)";
|
||||
} elseif ($item->end_at && Carbon::parse($item->end_at)->lt(Carbon::now())) {
|
||||
$status = " (已过期)";
|
||||
}
|
||||
return " - {$item->name} {$status}";
|
||||
})->join("\n");
|
||||
if ($subTaskContent) {
|
||||
$before_text[] = <<<EOF
|
||||
子任务列表:
|
||||
{$subTaskContent}
|
||||
EOF;
|
||||
}
|
||||
}
|
||||
$before_text[] = <<<EOF
|
||||
如果你判断我想要添加子任务,请将子任务标题添加到回复中,例如:
|
||||
如果你判断我想要添加子任务,请按照以下格式回复:
|
||||
|
||||
::: create-subtask-list
|
||||
title: 子任务标题1
|
||||
title: 子任务标题2
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
namespace App\Tasks;
|
||||
|
||||
use App\Models\ApproveProcInstHistory;
|
||||
use App\Models\User;
|
||||
use App\Models\UserCheckinRecord;
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use App\Module\Base;
|
||||
use App\Module\Doo;
|
||||
use App\Module\Extranet;
|
||||
use App\Module\Timer;
|
||||
use Cache;
|
||||
@@ -82,6 +82,9 @@ class CheckinRemindTask extends AbstractTask
|
||||
if (!UserCheckinRecord::whereUserid($user->userid)->where('created_at', '>', Carbon::now()->subDays(3))->exists()) {
|
||||
continue; // 3天内没有打卡
|
||||
}
|
||||
if (ApproveProcInstHistory::userIsLeave($user->userid)) {
|
||||
continue; // 请假、外出
|
||||
}
|
||||
$dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid);
|
||||
if ($dialog) {
|
||||
if ($type === 'exceed') {
|
||||
|
||||
54
bin/https
@@ -142,6 +142,7 @@ install() {
|
||||
if /root/.acme.sh/acme.sh --installcert -d "${domain}" --fullchainpath "${sslPath}/${domain}.crt" --keypath "${sslPath}/${domain}.key" --ecc --force; then
|
||||
success "SSL 证书配置成功"
|
||||
sleep 2
|
||||
cp -r /root/.acme.sh/${domain}_ecc/*.conf ${sslPath}/
|
||||
fi
|
||||
else
|
||||
error "SSL 证书生成失败"
|
||||
@@ -165,5 +166,54 @@ error_page 497 https://\$host\$request_uri;
|
||||
EOF
|
||||
}
|
||||
|
||||
check
|
||||
install
|
||||
UPDATE_LOG="$(dirname "$PWD")/docker/nginx/site/ssl/update.log"
|
||||
SSL_PATH="$(dirname "$PWD")/docker/nginx/site/ssl"
|
||||
upgrade_cert(){
|
||||
curl https://get.acme.sh | sh
|
||||
if [[ 0 -ne $? ]]; then
|
||||
echo "安装证书更新脚本失败"
|
||||
echo $(date)": 安装证书更新脚本失败" >> ${UPDATE_LOG}
|
||||
exit 1
|
||||
fi
|
||||
file=$1
|
||||
domain=$(basename "$file" .key)
|
||||
old_crt_md5=$(md5sum ${SSL_PATH}/${domain}.crt| awk '{print $1}')
|
||||
/root/.acme.sh/acme.sh --renew --standalone -d ${domain} --fullchainpath "${SSL_PATH}/${domain}.crt" --keypath "${SSL_PATH}/${domain}.key" --ecc --force
|
||||
new_crt_md5=$(md5sum ${SSL_PATH}/${domain}.crt| awk '{print $1}')
|
||||
if [ "${old_key_md5}" == "${new_key_md5}" ]; then
|
||||
echo "${domain} 证书更新脚本失败"
|
||||
echo $(date)": ${domain} 证书更新失败" >> ${UPDATE_LOG}
|
||||
echo $(date)": ${old_crt_md5} == ${new_crt_md5}" >> ${UPDATE_LOG}
|
||||
else
|
||||
echo "${domain} 证书更新脚本成功"
|
||||
echo $(date)": ${domain} 证书更新成功" >> ${UPDATE_LOG}
|
||||
fi
|
||||
}
|
||||
|
||||
check_expire(){
|
||||
apk add --no-cache openssl socat
|
||||
find ${SSL_PATH} -type f -name "*.key" | while read -r file; do
|
||||
CERT_PATH=$file
|
||||
expiry_date=$(openssl x509 -enddate -noout -in "$CERT_PATH" | cut -d= -f2)
|
||||
expiry_timestamp=$(date -d "$expiry_date" +%s)
|
||||
current_timestamp=$(date +%s)
|
||||
days_remaining=$(( (expiry_timestamp - current_timestamp) / 86400 ))
|
||||
echo "剩余时间${days_remaining}天" >> ${UPDATE_LOG}
|
||||
if [ "$days_remaining" -lt 30 ]; then
|
||||
upgrade_cert $file
|
||||
fi
|
||||
done
|
||||
}
|
||||
case "${1}" in
|
||||
"install")
|
||||
check
|
||||
install
|
||||
;;
|
||||
"renew")
|
||||
check_expire
|
||||
;;
|
||||
*)
|
||||
echo "test"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
16
cmd
@@ -322,15 +322,26 @@ https_auto() {
|
||||
if [[ "$restart_nginx" == "y" ]]; then
|
||||
$COMPOSE up -d
|
||||
fi
|
||||
docker run -it --rm -v $(pwd):/work nginx:alpine sh "/work/bin/https"
|
||||
docker run -it --rm -v $(pwd):/work nginx:alpine sh /work/bin/https install
|
||||
if [[ 0 -eq $? ]]; then
|
||||
run_exec nginx "nginx -s reload"
|
||||
fi
|
||||
new_job="* 6 * * * docker run -it --rm -v $(pwd):/work nginx:alpine sh /work/bin/https renew"
|
||||
current_crontab=$(crontab -l 2>/dev/null)
|
||||
if ! echo "$current_crontab" | grep -v "https renew"; then
|
||||
echo "任务已存在,无需添加。"
|
||||
else
|
||||
crontab -l |{
|
||||
cat
|
||||
echo "$new_job"
|
||||
} | crontab -
|
||||
echo "任务已添加。"
|
||||
fi
|
||||
}
|
||||
|
||||
env_get() {
|
||||
local key=$1
|
||||
local value=`cat ${cur_path}/.env | grep "^$key=" | awk -F '=' '{print $2}'`
|
||||
local value=`cat ${cur_path}/.env | grep "^$key=" | awk -F '=' '{print $2}' | tr -d '\r\n'`
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
@@ -433,6 +444,7 @@ if [ $# -gt 0 ]; then
|
||||
error "数据库初始化失败!"
|
||||
exit 1
|
||||
fi
|
||||
sleep 3
|
||||
chmod -R 775 "${cur_path}/docker/mysql/data"
|
||||
done
|
||||
# 数据库迁移
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"ext-curl": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-imagick": "*",
|
||||
"ext-json": "*",
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddIsNotifiedToUmengAlias extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('umeng_alias', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('umeng_alias', 'is_notified')) {
|
||||
$table->tinyInteger('is_notified')->nullable()->default(0)->after('ua')->comment('通知权限');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('umeng_alias', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('umeng_alias', 'is_notified')) {
|
||||
$table->dropColumn('is_notified');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddVersionToUmengAlias extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('umeng_alias', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('umeng_alias', 'version')) {
|
||||
$table->string('version', 50)->nullable()->default('')->after('device')->comment('应用版本号');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('umeng_alias', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('umeng_alias', 'version')) {
|
||||
$table->dropColumn('version');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class UpdateProjectTasksSubtaskProjectIdAndColumnId extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$prefix = DB::getTablePrefix();
|
||||
$now = Carbon::now();
|
||||
DB::statement("
|
||||
UPDATE {$prefix}project_tasks AS subtask
|
||||
INNER JOIN {$prefix}project_tasks AS parent ON subtask.parent_id = parent.id
|
||||
SET
|
||||
subtask.project_id = parent.project_id,
|
||||
subtask.column_id = parent.column_id,
|
||||
subtask.updated_at = '{$now}'
|
||||
WHERE subtask.parent_id > 0
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// No need for down operation as this is a data correction
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class UpdateProjectTasksSubtaskVisibility extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$prefix = DB::getTablePrefix();
|
||||
$now = Carbon::now();
|
||||
DB::statement("
|
||||
UPDATE {$prefix}project_tasks AS subtask
|
||||
INNER JOIN {$prefix}project_tasks AS parent ON subtask.parent_id = parent.id
|
||||
SET
|
||||
subtask.visibility = parent.visibility,
|
||||
subtask.updated_at = '{$now}'
|
||||
WHERE subtask.parent_id > 0
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// No need for down operation as this is a data correction
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddBotToWebSocketDialogUsersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('web_socket_dialog_users', 'bot')) {
|
||||
$table->tinyInteger('bot')->nullable()->default(0)->after('userid')->comment('是否机器人');
|
||||
$table->index('bot');
|
||||
}
|
||||
});
|
||||
|
||||
// 获取表前缀
|
||||
$prefix = DB::getTablePrefix();
|
||||
|
||||
// 使用原生SQL更新数据
|
||||
/** @noinspection SqlNoDataSourceInspection */
|
||||
DB::statement("
|
||||
UPDATE {$prefix}web_socket_dialog_users du
|
||||
INNER JOIN {$prefix}users u ON u.userid = du.userid
|
||||
SET du.bot = 1
|
||||
WHERE u.bot = 1
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('web_socket_dialog_users', 'bot')) {
|
||||
$table->dropIndex('bot');
|
||||
$table->dropColumn('bot');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@ services:
|
||||
- ./docker/office/logs:/var/log/onlyoffice
|
||||
- ./docker/office/data:/var/www/onlyoffice/Data
|
||||
- ./docker/office/resources/require.js:/var/www/onlyoffice/documentserver/web-apps/vendor/requirejs/require.js
|
||||
- ./docker/office/resources/common/main/resources/img/header:/var/www/onlyoffice/documentserver/web-apps/apps/common/main/resources/img/header
|
||||
- ./docker/office/resources/documenteditor/main/resources/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/documenteditor/main/resources/css/app.css
|
||||
- ./docker/office/resources/documenteditor/mobile/css/526.caf35c11a8d72ca5ac85.css:/var/www/onlyoffice/documentserver/web-apps/apps/documenteditor/mobile/css/526.caf35c11a8d72ca5ac85.css
|
||||
- ./docker/office/resources/presentationeditor/main/resources/css/app.css:/var/www/onlyoffice/documentserver/web-apps/apps/presentationeditor/main/resources/css/app.css
|
||||
@@ -167,7 +168,7 @@ services:
|
||||
|
||||
ai:
|
||||
container_name: "dootask-ai-${APP_ID}"
|
||||
image: "kuaifan/dootask-ai:0.1.6"
|
||||
image: "kuaifan/dootask-ai:0.2.8"
|
||||
environment:
|
||||
REDIS_HOST: "${REDIS_HOST}"
|
||||
REDIS_PORT: "${REDIS_PORT}"
|
||||
|
||||
@@ -192,6 +192,10 @@ server {
|
||||
# AI
|
||||
location /ai/ {
|
||||
proxy_http_version 1.1;
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
proxy_read_timeout 300s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_set_header Scheme $scheme;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
|
||||
1
docker/office/resources/common/main/resources/img/header/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.gz
|
||||
@@ -0,0 +1,2 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="85" height="20" fill="none">
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 82 B |
@@ -0,0 +1,2 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="85" height="20" fill="none">
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 83 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="28" height="60"><symbol id="svg-icon-crypted" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M10 3C7 5 4 5 4 5v3.5c0 2 .563 7.477 6 8.5 5.436-1.023 6-6.5 6-8.5V5s-3 0-6-2m4.023 4.965-1.046-.93-3.55 3.993-2.479-2.066-.896 1.076 3.52 2.934z" clip-rule="evenodd"/></symbol><symbol id="svg-icon-users" viewBox="0 0 28 20"><path fill-rule="evenodd" d="M27 10a9 9 0 1 1-18 0 9 9 0 0 1 18 0m1 0c0 5.523-4.477 10-10 10a9.96 9.96 0 0 1-6.798-2.666 8 8 0 1 1 0-14.667A9.96 9.96 0 0 1 18 0c5.523 0 10 4.477 10 10M10.451 3.441A7 7 0 0 0 8 3a7 7 0 0 0-5.69 11.079 11 11 0 0 1 1.124-.76C4.544 12.666 6.132 12 8 12q.1 0 .2.003A10 10 0 0 1 8.05 11H8a3 3 0 1 1 1.198-5.751 10 10 0 0 1 1.253-1.808M8.767 6.152A2 2 0 0 0 8 6a2 2 0 1 0 0 4 10 10 0 0 1 .767-3.848m-.304 6.864A7 7 0 0 0 8 13c-1.632 0-3.043.584-4.059 1.181a10 10 0 0 0-.99.667A6.98 6.98 0 0 0 8 17a7 7 0 0 0 2.451-.441 10 10 0 0 1-1.988-3.543" clip-rule="evenodd"/></symbol></svg>
|
||||
|
After Width: | Height: | Size: 994 B |
1
electron/build.js
vendored
@@ -512,6 +512,7 @@ async function startBuild(data) {
|
||||
fse.copySync(path.resolve(__dirname, "../public/language"), path.resolve(electronDir, "language"))
|
||||
// config.js
|
||||
fs.writeFileSync(electronDir + "/config.js", "window.systemInfo = " + JSON.stringify(systemInfo), 'utf8');
|
||||
fs.writeFileSync(electronDir + "/dark", '', 'utf8');
|
||||
fs.writeFileSync(nativeCachePath, utils.formatUrl(data.url));
|
||||
fs.writeFileSync(devloadCachePath, "", 'utf8');
|
||||
// index.html
|
||||
|
||||
27
electron/electron.js
vendored
@@ -434,7 +434,7 @@ function createChildWindow(args) {
|
||||
if (/^https?:/i.test(hash)) {
|
||||
browser.loadURL(hash).then(_ => { }).catch(_ => { })
|
||||
} else if (isPreload) {
|
||||
browser.webContents.executeJavaScript(`if(typeof $A.goForward === 'function'){$A.goForward('${hash}')}else{throw new Error('no function')}`, true).catch(() => {
|
||||
browser.webContents.executeJavaScript(`if(typeof window.__initializeApp === 'function'){window.__initializeApp('${hash}')}else{throw new Error('no function')}`, true).catch(() => {
|
||||
utils.loadUrlOrFile(browser, devloadUrl, hash)
|
||||
});
|
||||
} else {
|
||||
@@ -556,8 +556,6 @@ function createWebTabWindow(args) {
|
||||
|
||||
// 创建父级窗口
|
||||
if (!webTabWindow) {
|
||||
let config = Object.assign(args.config || {}, userConf.get('webTabWindow', {}));
|
||||
let webPreferences = args.webPreferences || {};
|
||||
const titleBarOverlay = {
|
||||
height: webTabHeight
|
||||
}
|
||||
@@ -578,14 +576,14 @@ function createWebTabWindow(args) {
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay,
|
||||
backgroundColor: nativeTheme.shouldUseDarkColors ? '#3B3B3D' : '#EFF0F4',
|
||||
webPreferences: Object.assign({
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'electron-preload.js'),
|
||||
webSecurity: true,
|
||||
nodeIntegration: true,
|
||||
contextIsolation: true,
|
||||
nativeWindowOpen: true
|
||||
}, webPreferences),
|
||||
}, config))
|
||||
},
|
||||
}, userConf.get('webTabWindow', {})))
|
||||
|
||||
webTabWindow.on('resize', () => {
|
||||
resizeWebTab(0)
|
||||
@@ -650,15 +648,20 @@ function createWebTabWindow(args) {
|
||||
webTabWindow.show();
|
||||
|
||||
// 创建 tab 子窗口
|
||||
const browserView = new BrowserView({
|
||||
const viewOptions = Object.assign({
|
||||
useHTMLTitleAndIcon: true,
|
||||
useLoadingView: true,
|
||||
useErrorView: true,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'electron-preload.js'),
|
||||
}
|
||||
})
|
||||
if (nativeTheme.shouldUseDarkColors) {
|
||||
}, args.config || {})
|
||||
viewOptions.webPreferences = Object.assign({
|
||||
preload: path.join(__dirname, 'electron-preload.js'),
|
||||
nodeIntegration: true,
|
||||
contextIsolation: true
|
||||
}, args.webPreferences || {})
|
||||
const browserView = new BrowserView(viewOptions)
|
||||
if (args.backgroundColor) {
|
||||
browserView.setBackgroundColor(args.backgroundColor)
|
||||
} else if (nativeTheme.shouldUseDarkColors) {
|
||||
browserView.setBackgroundColor('#575757')
|
||||
} else {
|
||||
browserView.setBackgroundColor('#FFFFFF')
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<title></title>
|
||||
<!--style-->
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"@electron-forge/maker-squirrel": "^7.6.0",
|
||||
"@electron-forge/maker-zip": "^7.6.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"electron": "^33.2.1",
|
||||
"electron": "^34.0.2",
|
||||
"electron-builder": "^25.1.8",
|
||||
"electron-notarize": "^1.2.2",
|
||||
"form-data": "^4.0.1",
|
||||
|
||||
@@ -37,13 +37,16 @@
|
||||
const {ipcRenderer} = require('electron');
|
||||
|
||||
const thumbnailUrl = (url) => {
|
||||
url = `${url}`
|
||||
.replace(/_thumb\.(png|jpg|jpeg)$/, '')
|
||||
.replace(/\/crop\/([^\/]+)$/, '')
|
||||
if (!/^https?:\/\/[^\/]+\/uploads\//.test(url)) {
|
||||
return url
|
||||
}
|
||||
const crops = {
|
||||
ratio: 3,
|
||||
percentage: '320x0'
|
||||
}
|
||||
url = `${url}`
|
||||
.replace(/_thumb\.(png|jpg|jpeg)$/, '')
|
||||
.replace(/\/crop\/([^\/]+)$/, '')
|
||||
return url + "/crop/" + Object.keys(crops).map(key => {
|
||||
return `${key}:${crops[key]}`
|
||||
}).join(",")
|
||||
|
||||
@@ -802,3 +802,6 @@ webhook地址最长仅支持255个字符。
|
||||
更新子任务标签
|
||||
|
||||
AI机器人不存在
|
||||
|
||||
内容不存在
|
||||
长文本
|
||||
|
||||
@@ -1903,3 +1903,24 @@ WiFi签到延迟时长为±1分钟。
|
||||
请选择示例标签
|
||||
全部保存成功
|
||||
|
||||
消息详情
|
||||
长文本
|
||||
你确定要创建任务吗?
|
||||
你确定要创建子任务吗?
|
||||
|
||||
正在处理,请稍后再试...
|
||||
|
||||
开启麦克风失败!
|
||||
开启摄像头失败!
|
||||
|
||||
群机器人
|
||||
群成员 ((*)人)
|
||||
此消息已经过期
|
||||
|
||||
DeepSeek大语言模型算法是北京深度求索人工智能基础技术研究有限公司推出的深度合成服务算法。
|
||||
请输入模型名称
|
||||
API请求的基础URL路径,如果没有请留空
|
||||
访问DeepSeek网站查看
|
||||
|
||||
欢迎词
|
||||
仪表盘欢迎词,(*)代表用户昵称
|
||||
|
||||
@@ -4815,13 +4815,13 @@
|
||||
"key": "超期未完成",
|
||||
"zh": "",
|
||||
"zh-CHT": "超期未完成",
|
||||
"en": "Overdue unfinished",
|
||||
"ko": "기한 초과 미완료",
|
||||
"ja": "期限切れ未完了",
|
||||
"de": "Überfällig unvollendet",
|
||||
"fr": "En retard non terminé",
|
||||
"id": "Terlambat belum selesai",
|
||||
"ru": "Просрочено незавершенное"
|
||||
"en": "Overdue",
|
||||
"ko": "기한 초과",
|
||||
"ja": "期限切れ",
|
||||
"de": "Überfällig",
|
||||
"fr": "En retard",
|
||||
"id": "Terlambat",
|
||||
"ru": "Просрочено"
|
||||
},
|
||||
{
|
||||
"key": "身份已失效",
|
||||
@@ -27910,5 +27910,209 @@
|
||||
"fr": "Le robot IA n'existe pas",
|
||||
"id": "Robot AI tidak ada",
|
||||
"ru": "ИИ-робот не существует"
|
||||
},
|
||||
{
|
||||
"key": "消息详情",
|
||||
"zh": "",
|
||||
"zh-CHT": "消息詳情",
|
||||
"en": "Message Details",
|
||||
"ko": "메시지 세부 사항",
|
||||
"ja": "メッセージの詳細",
|
||||
"de": "Nachrichtendetails",
|
||||
"fr": "Détails du message",
|
||||
"id": "Detail Pesan",
|
||||
"ru": "Детали сообщения"
|
||||
},
|
||||
{
|
||||
"key": "长文本",
|
||||
"zh": "",
|
||||
"zh-CHT": "長文本",
|
||||
"en": "Long Text",
|
||||
"ko": "긴 텍스트",
|
||||
"ja": "長いテキスト",
|
||||
"de": "Langer Text",
|
||||
"fr": "Texte Long",
|
||||
"id": "Teks Panjang",
|
||||
"ru": "Длинный текст"
|
||||
},
|
||||
{
|
||||
"key": "内容不存在",
|
||||
"zh": "",
|
||||
"zh-CHT": "內容不存在",
|
||||
"en": "Content does not exist",
|
||||
"ko": "내용이 존재하지 않음",
|
||||
"ja": "内容が存在しません",
|
||||
"de": "Inhalt existiert nicht",
|
||||
"fr": "Le contenu n'existe pas",
|
||||
"id": "Konten tidak ada",
|
||||
"ru": "Содержимое не существует"
|
||||
},
|
||||
{
|
||||
"key": "你确定要创建任务吗?",
|
||||
"zh": "",
|
||||
"zh-CHT": "你確定要創建任務嗎?",
|
||||
"en": "Are you sure you want to create a task?",
|
||||
"ko": "작업을 생성하시겠습니까?",
|
||||
"ja": "タスクを作成しますか?",
|
||||
"de": "Sind Sie sicher, dass Sie eine Aufgabe erstellen möchten?",
|
||||
"fr": "Êtes-vous sûr de vouloir créer une tâche ?",
|
||||
"id": "Anda yakin ingin membuat tugas?",
|
||||
"ru": "Вы уверены, что хотите создать задание?"
|
||||
},
|
||||
{
|
||||
"key": "你确定要创建子任务吗?",
|
||||
"zh": "",
|
||||
"zh-CHT": "你確定要創建子任務嗎?",
|
||||
"en": "Are you sure you want to create a subtask?",
|
||||
"ko": "하위 작업을 생성하시겠습니까?",
|
||||
"ja": "サブタスクを作成しますか?",
|
||||
"de": "Sind Sie sicher, dass Sie eine Teilaufgabe erstellen möchten?",
|
||||
"fr": "Êtes-vous sûr de vouloir créer une sous-tâche ?",
|
||||
"id": "Anda yakin ingin membuat sub-tugas?",
|
||||
"ru": "Вы уверены, что хотите создать подзадачу?"
|
||||
},
|
||||
{
|
||||
"key": "正在处理,请稍后再试...",
|
||||
"zh": "",
|
||||
"zh-CHT": "正在處理,請稍後再試...",
|
||||
"en": "Processing, please try again later...",
|
||||
"ko": "처리 중이니 잠시 후 다시 시도하세요...",
|
||||
"ja": "処理中です。しばらくしてからもう一度お試しください...",
|
||||
"de": "Wird bearbeitet, bitte versuchen Sie es später noch einmal...",
|
||||
"fr": "Traitement en cours, veuillez réessayer plus tard...",
|
||||
"id": "Sedang diproses, silakan coba lagi nanti...",
|
||||
"ru": "Обработка, пожалуйста, повторите попытку позже..."
|
||||
},
|
||||
{
|
||||
"key": "开启麦克风失败!",
|
||||
"zh": "",
|
||||
"zh-CHT": "開啟麥克風失敗!",
|
||||
"en": "Failed to turn on the microphone!",
|
||||
"ko": "마이크 켜기에 실패했습니다!",
|
||||
"ja": "マイクの起動に失敗しました!",
|
||||
"de": "Das Einschalten des Mikrofons ist fehlgeschlagen!",
|
||||
"fr": "Échec de l'activation du microphone !",
|
||||
"id": "Gagal menghidupkan mikrofon!",
|
||||
"ru": "Не удалось включить микрофон!"
|
||||
},
|
||||
{
|
||||
"key": "开启摄像头失败!",
|
||||
"zh": "",
|
||||
"zh-CHT": "開啟攝像頭失敗!",
|
||||
"en": "Failed to turn on the camera!",
|
||||
"ko": "카메라 켜기에 실패했습니다!",
|
||||
"ja": "カメラの起動に失敗しました!",
|
||||
"de": "Das Einschalten der Kamera ist fehlgeschlagen!",
|
||||
"fr": "Échec de l'activation de la caméra !",
|
||||
"id": "Gagal menghidupkan kamera!",
|
||||
"ru": "Не удалось включить камеру!"
|
||||
},
|
||||
{
|
||||
"key": "群机器人",
|
||||
"zh": "",
|
||||
"zh-CHT": "群機器人",
|
||||
"en": "Group Bot",
|
||||
"ko": "그룹 봇",
|
||||
"ja": "グループボット",
|
||||
"de": "Gruppen-Bot",
|
||||
"fr": "Bot de groupe",
|
||||
"id": "Bot Grup",
|
||||
"ru": "Групповой бот"
|
||||
},
|
||||
{
|
||||
"key": "群成员 ((%T1)人)",
|
||||
"zh": "",
|
||||
"zh-CHT": "群成員 ((%T1)人)",
|
||||
"en": "Group members ((%T1) people)",
|
||||
"ko": "그룹 구성원 ((%T1)명)",
|
||||
"ja": "グループメンバー ((%T1)人)",
|
||||
"de": "Gruppenmitglieder ((%T1) Personen)",
|
||||
"fr": "Membres du groupe ((%T1) personnes)",
|
||||
"id": "Anggota grup ((%T1) orang)",
|
||||
"ru": "Участники группы ((%T1) человек)"
|
||||
},
|
||||
{
|
||||
"key": "此消息已经过期",
|
||||
"zh": "",
|
||||
"zh-CHT": "此消息已經過期",
|
||||
"en": "This message has expired",
|
||||
"ko": "이 메시지는 만료되었습니다",
|
||||
"ja": "このメッセージは有効期限が切れました",
|
||||
"de": "Diese Nachricht ist abgelaufen",
|
||||
"fr": "Ce message a expiré",
|
||||
"id": "Pesan ini telah kedaluwarsa",
|
||||
"ru": "Это сообщение истекло"
|
||||
},
|
||||
{
|
||||
"key": "DeepSeek大语言模型算法是北京深度求索人工智能基础技术研究有限公司推出的深度合成服务算法。",
|
||||
"zh": "",
|
||||
"zh-CHT": "DeepSeek大語言模型算法是北京深度求索人工智能基礎技術研究有限公司推出的深度合成服務算法。",
|
||||
"en": "The DeepSeek large language model algorithm is a deep synthesis service algorithm launched by Beijing Deep Exploration Artificial Intelligence Foundation Technology Research Co., Ltd.",
|
||||
"ko": "DeepSeek 대형 언어 모델 알고리즘은 베이징 딥 익스플로레이션 인공지능 기반 기술 연구 유한회사에서 출시한 심층 합성 서비스 알고리즘입니다.",
|
||||
"ja": "DeepSeek大言語モデルアルゴリズムは、北京深度探索人工知能基盤技術研究有限公司によって発表された深層合成サービスアルゴリズムです。",
|
||||
"de": "Der DeepSeek-Großsprachenmodellalgorithmus ist ein von der Beijing Deep Exploration Artificial Intelligence Foundation Technology Research Co., Ltd. entwickelter Tiefensynthese-Dienstalgorithmus.",
|
||||
"fr": "L'algorithme de modèle de langage grande échelle DeepSeek est un algorithme de service de synthèse profonde lancé par Beijing Deep Exploration Artificial Intelligence Foundation Technology Research Co., Ltd.",
|
||||
"id": "Algoritma model bahasa besar DeepSeek adalah algoritma layanan sintesis dalam yang diluncurkan oleh Beijing Deep Exploration Artificial Intelligence Foundation Technology Research Co., Ltd.",
|
||||
"ru": "Алгоритм крупной языковой модели DeepSeek является алгоритмом службы глубокого синтеза, разработанным Beijing Deep Exploration Artificial Intelligence Foundation Technology Research Co., Ltd."
|
||||
},
|
||||
{
|
||||
"key": "请输入模型名称",
|
||||
"zh": "",
|
||||
"zh-CHT": "請輸入模型名稱",
|
||||
"en": "Please enter the model name",
|
||||
"ko": "모델 이름을 입력하세요",
|
||||
"ja": "モデル名を入力してください",
|
||||
"de": "Bitte geben Sie den Modellnamen ein",
|
||||
"fr": "Veuillez entrer le nom du modèle",
|
||||
"id": "Silakan masukkan nama model",
|
||||
"ru": "Пожалуйста, введите название модели"
|
||||
},
|
||||
{
|
||||
"key": "API请求的基础URL路径,如果没有请留空",
|
||||
"zh": "",
|
||||
"zh-CHT": "API請求的基礎URL路徑,如果沒有請留空",
|
||||
"en": "Base URL path for API request, leave blank if none",
|
||||
"ko": "API 요청의 기본 URL 경로, 없으면 비워 두세요",
|
||||
"ja": "APIリクエストの基本URLパス、ない場合は空白のままにしてください",
|
||||
"de": "Basis-URL-Pfad für API-Anfragen, leer lassen, wenn nicht vorhanden",
|
||||
"fr": "Chemin d'URL de base pour la demande d'API, laisser vide si aucun",
|
||||
"id": "Jalur URL dasar untuk permintaan API, biarkan kosong jika tidak ada",
|
||||
"ru": "Базовый путь URL для запроса API, оставить пустым, если отсутствует"
|
||||
},
|
||||
{
|
||||
"key": "访问DeepSeek网站查看",
|
||||
"zh": "",
|
||||
"zh-CHT": "訪問DeepSeek網站查看",
|
||||
"en": "Visit the DeepSeek website to view",
|
||||
"ko": "DeepSeek 웹사이트 방문하여 보기",
|
||||
"ja": "DeepSeekのウェブサイトを訪問して確認してください",
|
||||
"de": "Besuchen Sie die DeepSeek-Website, um zu sehen",
|
||||
"fr": "Visitez le site Web de DeepSeek pour voir",
|
||||
"id": "Kunjungi situs web DeepSeek untuk melihat",
|
||||
"ru": "Посетите веб-сайт DeepSeek, чтобы просмотреть"
|
||||
},
|
||||
{
|
||||
"key": "欢迎词",
|
||||
"zh": "",
|
||||
"zh-CHT": "歡迎詞",
|
||||
"en": "Welcome Message",
|
||||
"ko": "환영 메시지",
|
||||
"ja": "歓迎メッセージ",
|
||||
"de": "Begrüßungsnachricht",
|
||||
"fr": "Message de bienvenue",
|
||||
"id": "Pesan Selamat Datang",
|
||||
"ru": "Приветственное сообщение"
|
||||
},
|
||||
{
|
||||
"key": "仪表盘欢迎词,(%T1)代表用户昵称",
|
||||
"zh": "",
|
||||
"zh-CHT": "儀表盤歡迎詞,(%T1)代表用戶暱稱",
|
||||
"en": "Dashboard welcome message, where (%T1) represents the user nickname",
|
||||
"ko": "대시보드 환영 메시지, (%T1)은 사용자 닉네임을 나타냅니다",
|
||||
"ja": "ダッシュボードの歓迎メッセージ、(%T1) はユーザーのニックネームを表します",
|
||||
"de": "Willkommensnachricht im Dashboard, wobei (%T1) den Benutzernamen darstellt",
|
||||
"fr": "Message de bienvenue sur le tableau de bord, où (%T1) représente le surnom de l'utilisateur",
|
||||
"id": "Pesan selamat datang di dasbor, di mana (%T1) mewakili julukan pengguna",
|
||||
"ru": "Приветственное сообщение на панели управления, где (%T1) представляет собой никнейм пользователя"
|
||||
}
|
||||
]
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "DooTask",
|
||||
"version": "0.41.55",
|
||||
"codeVerson": 158,
|
||||
"version": "0.42.57",
|
||||
"codeVerson": 166,
|
||||
"description": "DooTask is task management system.",
|
||||
"scripts": {
|
||||
"start": "./cmd dev",
|
||||
@@ -39,13 +39,13 @@
|
||||
"internal-ip": "^6.2.0",
|
||||
"jquery": "^3.6.4",
|
||||
"jspdf": "^2.5.1",
|
||||
"le5le-store": "^1.0.7",
|
||||
"less": "^4.1.2",
|
||||
"less-loader": "^10.2.0",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-it": "^14.1.0",
|
||||
"markdown-it-link-attributes": "^4.0.1",
|
||||
"mitt": "^3.0.1",
|
||||
"notification-koro1": "^1.1.1",
|
||||
"openpgp_hi": "^5.7.0-1",
|
||||
"photoswipe": "^5.2.8",
|
||||
@@ -60,7 +60,7 @@
|
||||
"stylus-loader": "^7.1.0",
|
||||
"tinymce": "^5.10.3",
|
||||
"tui-calendar-hi": "^1.15.1-5",
|
||||
"view-design-hi": "^4.7.0-59",
|
||||
"view-design-hi": "^4.7.0-60",
|
||||
"vite": "^2.9.15",
|
||||
"vite-plugin-file-copy": "^1.0.0",
|
||||
"vite-plugin-require": "^1.1.10",
|
||||
|
||||
BIN
public/images/avatar/default_deepseek.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 489 KiB |
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 239 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 495 KiB |
BIN
public/images/emoticon/18/35.gif
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
public/images/emoticon/18/36.gif
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
public/images/emoticon/18/37.gif
Normal file
|
After Width: | Height: | Size: 229 KiB |
BIN
public/images/emoticon/18/38.gif
Normal file
|
After Width: | Height: | Size: 446 KiB |
BIN
public/images/emoticon/18/39.gif
Normal file
|
After Width: | Height: | Size: 153 KiB |
BIN
public/images/emoticon/18/40.gif
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
public/images/emoticon/18/41.gif
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
public/images/emoticon/18/42.gif
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
public/images/emoticon/18/43.gif
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
public/images/emoticon/18/44.gif
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
public/images/emoticon/18/45.gif
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
public/images/emoticon/18/46.gif
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
public/images/emoticon/18/47.gif
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
public/images/emoticon/18/48.gif
Normal file
|
After Width: | Height: | Size: 138 KiB |
1
public/js/build/404.8c51613d.js
vendored
@@ -1 +0,0 @@
|
||||
import{n as e}from"./app.01c506d5.js";import"./@micro-zoe.c2e1472d.js";import"./jquery.7bd86b3f.js";import"./@babel.f9bcab46.js";import"./dayjs.54df6ed8.js";import"./localforage.2b5bddcf.js";import"./markdown-it.bda97caf.js";import"./mdurl.ce6c1dd8.js";import"./uc.micro.8d343c98.js";import"./entities.48a44fec.js";import"./linkify-it.c5e8196e.js";import"./punycode.js.4b3f125a.js";import"./highlight.js.ab8aeea4.js";import"./markdown-it-link-attributes.e1d5d151.js";import"./@traptitech.897ae552.js";import"./vue.fd9b772e.js";import"./vuex.cc7cb26e.js";import"./openpgp_hi.15f91b1d.js";import"./axios.6ec123f8.js";import"./le5le-store.b40f9152.js";import"./vue-router.2d566cd7.js";import"./vue-clipboard2.50be9c5e.js";import"./clipboard.058ef547.js";import"./view-design-hi.dbfb3540.js";import"./vuedraggable.9fd6afed.js";import"./sortablejs.d74243d9.js";import"./vue-resize-observer.c3c9ca4e.js";import"./element-sea.7f208f9b.js";import"./deepmerge.cecf392e.js";import"./resize-observer-polyfill.0bdc1850.js";import"./throttle-debounce.7c3948b2.js";import"./babel-helper-vue-jsx-merge-props.5ed215c3.js";import"./normalize-wheel.2a034b9f.js";import"./async-validator.49abba38.js";import"./babel-runtime.4773988a.js";import"./core-js.314b4a1d.js";var m=function(){var t=this,r=t.$createElement;return t._self._c,t._m(0)},p=[function(){var t=this,r=t.$createElement,i=t._self._c||r;return i("div",{staticClass:"page-404"},[i("div",{staticClass:"flex-center position-ref full-height"},[i("div",{staticClass:"code"},[t._v("404")]),i("div",{staticClass:"message"},[t._v("Not Found")])])])}];const s={},o={};var _=e(s,m,p,!1,n,"7d7154a8",null,null);function n(t){for(let r in o)this[r]=o[r]}var Q=function(){return _.exports}();export{Q as default};
|
||||
1
public/js/build/404.dad5ee12.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import{n as e}from"./app.84e898f6.js";import"./@micro-zoe.c2e1472d.js";import"./jquery.0e77e8ff.js";import"./@babel.f9bcab46.js";import"./dayjs.65914b7a.js";import"./localforage.f2941043.js";import"./markdown-it.bda97caf.js";import"./mdurl.ce6c1dd8.js";import"./uc.micro.8d343c98.js";import"./entities.48a44fec.js";import"./linkify-it.c5e8196e.js";import"./punycode.js.4b3f125a.js";import"./highlight.js.ab8aeea4.js";import"./markdown-it-link-attributes.e1d5d151.js";import"./@traptitech.897ae552.js";import"./vue.fd9b772e.js";import"./vuex.cc7cb26e.js";import"./openpgp_hi.15f91b1d.js";import"./axios.6ec123f8.js";import"./mitt.1ea0a2a3.js";import"./vue-router.2d566cd7.js";import"./vue-clipboard2.50be9c5e.js";import"./clipboard.058ef547.js";import"./view-design-hi.0cb8d723.js";import"./vuedraggable.9fd6afed.js";import"./sortablejs.d74243d9.js";import"./vue-resize-observer.c3c9ca4e.js";import"./element-sea.7f208f9b.js";import"./deepmerge.cecf392e.js";import"./resize-observer-polyfill.0bdc1850.js";import"./throttle-debounce.7c3948b2.js";import"./babel-helper-vue-jsx-merge-props.5ed215c3.js";import"./normalize-wheel.2a034b9f.js";import"./async-validator.49abba38.js";import"./babel-runtime.4773988a.js";import"./core-js.314b4a1d.js";var m=function(){var t=this,r=t.$createElement;return t._self._c,t._m(0)},p=[function(){var t=this,r=t.$createElement,i=t._self._c||r;return i("div",{staticClass:"page-404"},[i("div",{staticClass:"flex-center position-ref full-height"},[i("div",{staticClass:"code"},[t._v("404")]),i("div",{staticClass:"message"},[t._v("Not Found")])])])}];const s={},o={};var _=e(s,m,p,!1,n,"7d7154a8",null,null);function n(t){for(let r in o)this[r]=o[r]}var Q=function(){return _.exports}();export{Q as default};
|
||||
1
public/js/build/AceEditor.1aa4eb34.js
vendored
1
public/js/build/AceEditor.a767f934.js
vendored
Normal file
7
public/js/build/DialogWrapper.3c314f38.js
vendored
7
public/js/build/DialogWrapper.cc68d864.js
vendored
Normal file
1
public/js/build/Drawio.107bddf8.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
import{m as s}from"./vuex.cc7cb26e.js";import{I as m}from"./IFrame.0e692d55.js";import{n as l,l as r}from"./app.84e898f6.js";import"./@micro-zoe.c2e1472d.js";import"./jquery.0e77e8ff.js";import"./@babel.f9bcab46.js";import"./dayjs.65914b7a.js";import"./localforage.f2941043.js";import"./markdown-it.bda97caf.js";import"./mdurl.ce6c1dd8.js";import"./uc.micro.8d343c98.js";import"./entities.48a44fec.js";import"./linkify-it.c5e8196e.js";import"./punycode.js.4b3f125a.js";import"./highlight.js.ab8aeea4.js";import"./markdown-it-link-attributes.e1d5d151.js";import"./@traptitech.897ae552.js";import"./vue.fd9b772e.js";import"./openpgp_hi.15f91b1d.js";import"./axios.6ec123f8.js";import"./mitt.1ea0a2a3.js";import"./vue-router.2d566cd7.js";import"./vue-clipboard2.50be9c5e.js";import"./clipboard.058ef547.js";import"./view-design-hi.0cb8d723.js";import"./vuedraggable.9fd6afed.js";import"./sortablejs.d74243d9.js";import"./vue-resize-observer.c3c9ca4e.js";import"./element-sea.7f208f9b.js";import"./deepmerge.cecf392e.js";import"./resize-observer-polyfill.0bdc1850.js";import"./throttle-debounce.7c3948b2.js";import"./babel-helper-vue-jsx-merge-props.5ed215c3.js";import"./normalize-wheel.2a034b9f.js";import"./async-validator.49abba38.js";import"./babel-runtime.4773988a.js";import"./core-js.314b4a1d.js";var p=function(){var t=this,e=t.$createElement,i=t._self._c||e;return i("div",{staticClass:"drawio-content"},[i("IFrame",{ref:"frame",staticClass:"drawio-iframe",attrs:{src:t.url},on:{"on-message":t.onMessage}}),t.loadIng?i("div",{staticClass:"drawio-loading"},[i("Loading")],1):t._e()],1)},d=[];const u={name:"Drawio",components:{IFrame:m},props:{value:{type:Object,default:function(){return{}}},title:{type:String,default:""},readOnly:{type:Boolean,default:!1}},data(){return{loadIng:!0,url:null,bakData:""}},created(){let t=r;switch(r){case"zh-CHT":t="zh-tw";break}let e=this.readOnly?1:0,i=this.readOnly?0:1,n=this.themeName==="dark"?"dark":"kennedy",a=`?title=${this.title?encodeURIComponent(this.title):""}&chrome=${i}&lightbox=${e}&ui=${n}&lang=${t}&offline=1&pwa=0&embed=1&noLangIcon=1&noExitBtn=1&noSaveBtn=1&saveAndExit=0&spin=1&proto=json`;this.$Electron?this.url=$A.originUrl(`drawio/webapp/index.html${a}`):this.url=$A.mainUrl(`drawio/webapp/${a}`)},mounted(){window.addEventListener("message",this.handleMessage)},beforeDestroy(){window.removeEventListener("message",this.handleMessage)},watch:{value:{handler(t){this.bakData!=$A.jsonStringify(t)&&(this.bakData=$A.jsonStringify(t),this.updateContent())},deep:!0}},computed:{...s(["themeName"])},methods:{formatZoom(t){return t+"%"},updateContent(){this.$refs.frame.postMessage(JSON.stringify({action:"load",autosave:1,xml:this.value.xml}))},onMessage(t){switch(t.event){case"init":this.loadIng=!1,this.updateContent();break;case"load":typeof this.value.xml=="undefined"&&this.$refs.frame.postMessage(JSON.stringify({action:"template"}));break;case"autosave":const e={xml:t.xml};this.bakData=$A.jsonStringify(e),this.$emit("input",e);break;case"save":this.$emit("saveData");break}}}},o={};var c=l(u,p,d,!1,h,"39021859",null,null);function h(t){for(let e in o)this[e]=o[e]}var Y=function(){return c.exports}();export{Y as default};
|
||||
1
public/js/build/Drawio.a7f85d69.js
vendored
@@ -1 +0,0 @@
|
||||
import{m as s}from"./vuex.cc7cb26e.js";import{I as m}from"./IFrame.19bca292.js";import{n as l,l as r}from"./app.01c506d5.js";import"./@micro-zoe.c2e1472d.js";import"./jquery.7bd86b3f.js";import"./@babel.f9bcab46.js";import"./dayjs.54df6ed8.js";import"./localforage.2b5bddcf.js";import"./markdown-it.bda97caf.js";import"./mdurl.ce6c1dd8.js";import"./uc.micro.8d343c98.js";import"./entities.48a44fec.js";import"./linkify-it.c5e8196e.js";import"./punycode.js.4b3f125a.js";import"./highlight.js.ab8aeea4.js";import"./markdown-it-link-attributes.e1d5d151.js";import"./@traptitech.897ae552.js";import"./vue.fd9b772e.js";import"./openpgp_hi.15f91b1d.js";import"./axios.6ec123f8.js";import"./le5le-store.b40f9152.js";import"./vue-router.2d566cd7.js";import"./vue-clipboard2.50be9c5e.js";import"./clipboard.058ef547.js";import"./view-design-hi.dbfb3540.js";import"./vuedraggable.9fd6afed.js";import"./sortablejs.d74243d9.js";import"./vue-resize-observer.c3c9ca4e.js";import"./element-sea.7f208f9b.js";import"./deepmerge.cecf392e.js";import"./resize-observer-polyfill.0bdc1850.js";import"./throttle-debounce.7c3948b2.js";import"./babel-helper-vue-jsx-merge-props.5ed215c3.js";import"./normalize-wheel.2a034b9f.js";import"./async-validator.49abba38.js";import"./babel-runtime.4773988a.js";import"./core-js.314b4a1d.js";var p=function(){var t=this,e=t.$createElement,i=t._self._c||e;return i("div",{staticClass:"drawio-content"},[i("IFrame",{ref:"frame",staticClass:"drawio-iframe",attrs:{src:t.url},on:{"on-message":t.onMessage}}),t.loadIng?i("div",{staticClass:"drawio-loading"},[i("Loading")],1):t._e()],1)},d=[];const u={name:"Drawio",components:{IFrame:m},props:{value:{type:Object,default:function(){return{}}},title:{type:String,default:""},readOnly:{type:Boolean,default:!1}},data(){return{loadIng:!0,url:null,bakData:""}},created(){let t=r;switch(r){case"zh-CHT":t="zh-tw";break}let e=this.readOnly?1:0,i=this.readOnly?0:1,n=this.themeName==="dark"?"dark":"kennedy",a=`?title=${this.title?encodeURIComponent(this.title):""}&chrome=${i}&lightbox=${e}&ui=${n}&lang=${t}&offline=1&pwa=0&embed=1&noLangIcon=1&noExitBtn=1&noSaveBtn=1&saveAndExit=0&spin=1&proto=json`;this.$Electron?this.url=$A.originUrl(`drawio/webapp/index.html${a}`):this.url=$A.mainUrl(`drawio/webapp/${a}`)},mounted(){window.addEventListener("message",this.handleMessage)},beforeDestroy(){window.removeEventListener("message",this.handleMessage)},watch:{value:{handler(t){this.bakData!=$A.jsonStringify(t)&&(this.bakData=$A.jsonStringify(t),this.updateContent())},deep:!0}},computed:{...s(["themeName"])},methods:{formatZoom(t){return t+"%"},updateContent(){this.$refs.frame.postMessage(JSON.stringify({action:"load",autosave:1,xml:this.value.xml}))},onMessage(t){switch(t.event){case"init":this.loadIng=!1,this.updateContent();break;case"load":typeof this.value.xml=="undefined"&&this.$refs.frame.postMessage(JSON.stringify({action:"template"}));break;case"autosave":const e={xml:t.xml};this.bakData=$A.jsonStringify(e),this.$emit("input",e);break;case"save":this.$emit("saveData");break}}}},o={};var c=l(u,p,d,!1,h,"39021859",null,null);function h(t){for(let e in o)this[e]=o[e]}var Y=function(){return c.exports}();export{Y as default};
|
||||
1
public/js/build/FileContent.3fbbbae8.js
vendored
Normal file
1
public/js/build/FileContent.efa77165.js
vendored
1
public/js/build/FilePreview.10709028.js
vendored
Normal file
1
public/js/build/FilePreview.22b0c37c.js
vendored
@@ -1 +1 @@
|
||||
import{n}from"./app.01c506d5.js";var i=function(){var e=this,s=e.$createElement,r=e._self._c||s;return r("iframe",{directives:[{name:"show",rawName:"v-show",value:e.src,expression:"src"}],ref:"iframe",attrs:{src:e.src}})},a=[];const o={name:"IFrame",props:{src:{type:String,default:""}},mounted(){this.$refs.iframe.addEventListener("load",this.handleLoad),window.addEventListener("message",this.handleMessage)},beforeDestroy(){this.$refs.iframe.removeEventListener("load",this.handleLoad),window.removeEventListener("message",this.handleMessage)},methods:{handleLoad(){this.$emit("on-load")},handleMessage({data:e,source:s}){var r;s===((r=this.$refs.iframe)==null?void 0:r.contentWindow)&&(e=$A.jsonParse(e),e.source==="fileView"&&e.action==="picture"&&this.$store.dispatch("previewImage",{index:e.params.index,list:e.params.array}),this.$emit("on-message",e))},postMessage(e,s="*"){this.$refs.iframe&&this.$refs.iframe.contentWindow.postMessage(e,s)}}},t={};var m=n(o,i,a,!1,c,null,null,null);function c(e){for(let s in t)this[s]=t[s]}var l=function(){return m.exports}();export{l as I};
|
||||
import{n}from"./app.84e898f6.js";var i=function(){var e=this,s=e.$createElement,r=e._self._c||s;return r("iframe",{directives:[{name:"show",rawName:"v-show",value:e.src,expression:"src"}],ref:"iframe",attrs:{src:e.src}})},a=[];const o={name:"IFrame",props:{src:{type:String,default:""}},mounted(){this.$refs.iframe.addEventListener("load",this.handleLoad),window.addEventListener("message",this.handleMessage)},beforeDestroy(){this.$refs.iframe.removeEventListener("load",this.handleLoad),window.removeEventListener("message",this.handleMessage)},methods:{handleLoad(){this.$emit("on-load")},handleMessage({data:e,source:s}){var r;s===((r=this.$refs.iframe)==null?void 0:r.contentWindow)&&(e=$A.jsonParse(e),e.source==="fileView"&&e.action==="picture"&&this.$store.dispatch("previewImage",{index:e.params.index,list:e.params.array}),this.$emit("on-message",e))},postMessage(e,s="*"){this.$refs.iframe&&this.$refs.iframe.contentWindow.postMessage(e,s)}}},t={};var m=n(o,i,a,!1,c,null,null,null);function c(e){for(let s in t)this[s]=t[s]}var l=function(){return m.exports}();export{l as I};
|
||||
@@ -1 +1 @@
|
||||
import{V as p}from"./vue.fd9b772e.js";import{s,U as o,a as r,l as n,n as h}from"./app.01c506d5.js";import{m as l}from"./vuex.cc7cb26e.js";import{u as d,E as u}from"./@micro-zoe.c2e1472d.js";import{D as m}from"./DialogWrapper.3c314f38.js";import{i as c}from"./view-design-hi.dbfb3540.js";var f=function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("div",{staticClass:"page-microapp"},[a.showSpin?e("transition",{attrs:{name:"microapp-load"}},[e("div",{staticClass:"microapp-load"},[e("Loading")],1)]):a._e(),a.url&&!a.loading?e("micro-app",{attrs:{name:a.name,url:a.url,inline:"","keep-alive":"",disableSandbox:"",data:a.appData},on:{created:a.handleCreate,beforemount:a.handleBeforeMount,mounted:a.handleMount,unmount:a.handleUnmount,error:a.handleError,datachange:a.handleDataChange}}):a._e()],1)},g=[];const w={name:"MicroApps",props:{name:{type:String,default:"micro-app"},url:{type:String,default:""},path:{type:String,default:""},datas:{type:Object,default:()=>{}}},data(){return{showSpin:!1,loading:!1,appData:{}}},mounted(){this.showSpin=!0,this.appData=this.getAppData},watch:{loading(a){a&&(this.showSpin=!0)},path(a){this.appData={path:a}},datas:{handler(a){this.appData=a},deep:!0},$route:{handler(a){(a.name=="manage-apps"||a.name=="single-apps")&&(this.appData={path:a.hash||a.fullPath})},immediate:!0},userToken(a){this.appData=this.getAppData,a?this.loading=!1:(d({destroy:!0}),this.loading=!0)}},computed:{...l(["userInfo","themeName"]),getAppData(){return{type:"init",url:this.url,vues:{Vue:p,store:s,components:{DialogWrapper:m,UserSelect:o,DatePicker:c.exports.DatePicker}},theme:this.themeName,languages:{languageList:r,languageName:n,languageType:n},userInfo:this.userInfo,path:this.path,electron:this.$Electron,openAppChildPage:a=>{this.$store.dispatch("openAppChildPage",a)},openChildWindow:a=>{this.$store.dispatch("openChildWindow",a)},openWebTabWindow:a=>{this.$store.dispatch("openWebTabWindow",a)}}}},methods:{handleCreate(a){window.eventCenterForAppNameVite=new u(a.detail.name),this.appData=this.getAppData,this.showSpin=!window["eventCenterForAppNameViteLoad-"+a.detail.name]},handleBeforeMount(a){window["eventCenterForAppNameViteLoad-"+a.detail.name]=1},handleMount(a){this.datas&&(this.appData=this.datas),this.path&&(this.appData.path=this.path),this.showSpin=!1},handleUnmount(a){window.dispatchEvent(new Event("apps-unmount"))},handleError(a){},handleDataChange(a){}}},i={};var v=h(w,f,g,!1,D,null,null,null);function D(a){for(let t in i)this[t]=i[t]}var y=function(){return v.exports}();export{y as M};
|
||||
import{V as p}from"./vue.fd9b772e.js";import{s,U as o,a as r,l as n,n as h}from"./app.84e898f6.js";import{m as l}from"./vuex.cc7cb26e.js";import{u as d,E as u}from"./@micro-zoe.c2e1472d.js";import{D as m}from"./DialogWrapper.cc68d864.js";import{i as c}from"./view-design-hi.0cb8d723.js";var f=function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("div",{staticClass:"page-microapp"},[a.showSpin?e("transition",{attrs:{name:"microapp-load"}},[e("div",{staticClass:"microapp-load"},[e("Loading")],1)]):a._e(),a.url&&!a.loading?e("micro-app",{attrs:{name:a.name,url:a.url,inline:"","keep-alive":"",disableSandbox:"",data:a.appData},on:{created:a.handleCreate,beforemount:a.handleBeforeMount,mounted:a.handleMount,unmount:a.handleUnmount,error:a.handleError,datachange:a.handleDataChange}}):a._e()],1)},g=[];const w={name:"MicroApps",props:{name:{type:String,default:"micro-app"},url:{type:String,default:""},path:{type:String,default:""},datas:{type:Object,default:()=>{}}},data(){return{showSpin:!1,loading:!1,appData:{}}},mounted(){this.showSpin=!0,this.appData=this.getAppData},watch:{loading(a){a&&(this.showSpin=!0)},path(a){this.appData={path:a}},datas:{handler(a){this.appData=a},deep:!0},$route:{handler(a){(a.name=="manage-apps"||a.name=="single-apps")&&(this.appData={path:a.hash||a.fullPath})},immediate:!0},userToken(a){this.appData=this.getAppData,a?this.loading=!1:(d({destroy:!0}),this.loading=!0)}},computed:{...l(["userInfo","themeName"]),getAppData(){return{type:"init",url:this.url,vues:{Vue:p,store:s,components:{DialogWrapper:m,UserSelect:o,DatePicker:c.exports.DatePicker}},theme:this.themeName,languages:{languageList:r,languageName:n,languageType:n},userInfo:this.userInfo,path:this.path,electron:this.$Electron,openAppChildPage:a=>{this.$store.dispatch("openAppChildPage",a)},openChildWindow:a=>{this.$store.dispatch("openChildWindow",a)},openWebTabWindow:a=>{this.$store.dispatch("openWebTabWindow",a)}}}},methods:{handleCreate(a){window.eventCenterForAppNameVite=new u(a.detail.name),this.appData=this.getAppData,this.showSpin=!window["eventCenterForAppNameViteLoad-"+a.detail.name]},handleBeforeMount(a){window["eventCenterForAppNameViteLoad-"+a.detail.name]=1},handleMount(a){this.datas&&(this.appData=this.datas),this.path&&(this.appData.path=this.path),this.showSpin=!1},handleUnmount(a){window.dispatchEvent(new Event("apps-unmount"))},handleError(a){},handleDataChange(a){}}},i={};var v=h(w,f,g,!1,D,null,null,null);function D(a){for(let t in i)this[t]=i[t]}var y=function(){return v.exports}();export{y as M};
|
||||
1
public/js/build/Minder.a237400a.js
vendored
1
public/js/build/Minder.f6908ac0.js
vendored
Normal file
1
public/js/build/OnlyOffice.32abaacf.js
vendored
Normal file
@@ -1 +1 @@
|
||||
.component-only-office[data-v-394e9394]{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center}.component-only-office .placeholder[data-v-394e9394]{flex:1;width:100%;height:100%}.component-only-office .office-loading[data-v-394e9394]{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;z-index:2}.component-only-office .load-error{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1;padding:8px;display:flex;align-items:center}.component-only-office .load-error .ivu-alert-icon{position:static;margin-right:8px;margin-left:4px}
|
||||
.component-only-office[data-v-7946f4cf]{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center}.component-only-office .placeholder[data-v-7946f4cf]{flex:1;width:100%;height:100%}.component-only-office .office-loading[data-v-7946f4cf]{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;z-index:2}.component-only-office .load-error{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1;padding:8px;display:flex;align-items:center}.component-only-office .load-error .ivu-alert-icon{position:static;margin-right:8px;margin-left:4px}
|
||||
1
public/js/build/OnlyOffice.7ba6b923.js
vendored
@@ -1 +1 @@
|
||||
import{m as i}from"./vuex.cc7cb26e.js";import{n as l}from"./app.01c506d5.js";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{staticClass:"report-detail"},[a("div",{staticClass:"report-title"},[t._v(" "+t._s(t.data.title)+" "),t.loadIng>0?a("Icon",{staticClass:"icon-loading",attrs:{type:"ios-loading"}}):t._e()],1),t.formOptions.labelWidth==="auto"?a("div",{staticClass:"report-detail-context"},[a("Form",{staticClass:"report-form auto-form",attrs:{"label-width":"auto",inline:""}},[a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u4EBA")}},[a("UserAvatar",{attrs:{userid:t.data.userid,size:28}})],1),a("FormItem",{attrs:{label:t.$L("\u63D0\u4EA4\u65F6\u95F4")}},[t._v(" "+t._s(t.data.created_at)+" ")]),a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u5BF9\u8C61")}},[t.data.receives_user.length===0?[t._v("-")]:t._l(t.data.receives_user,function(r,s){return a("UserAvatar",{key:s,attrs:{userid:r.userid,size:28}})})],2)],1),a("Form",{staticClass:"report-form auto-form",attrs:{"label-width":"auto"}},[a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u5185\u5BB9")}},[a("div",{staticClass:"report-content",domProps:{innerHTML:t._s(t.data.content)}})])],1)],1):a("div",{staticClass:"report-detail-context"},[a("Form",t._b({staticClass:"report-form"},"Form",t.formOptions,!1),[t.formOptions.labelWidth!=="auto"?[a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u4EBA")}},[a("UserAvatar",{attrs:{userid:t.data.userid,size:28}})],1),a("FormItem",{attrs:{label:t.$L("\u63D0\u4EA4\u65F6\u95F4")}},[t._v(" "+t._s(t.data.created_at)+" ")]),a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u5BF9\u8C61")}},[t.data.receives_user.length===0?[t._v("-")]:t._l(t.data.receives_user,function(r,s){return a("UserAvatar",{key:s,attrs:{userid:r.userid,size:28}})})],2)]:t._e(),a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u5185\u5BB9")}},[a("div",{staticClass:"report-content",domProps:{innerHTML:t._s(t.data.content)}})])],2)],1)])},d=[];const m={name:"ReportDetail",props:{data:{default:{}}},data(){return{loadIng:0}},computed:{...i(["formOptions"])},watch:{"data.id":{handler(t){t>0&&this.sendRead()},immediate:!0}},methods:{sendRead(){this.loadIng++,this.$store.dispatch("call",{url:"report/read",data:{ids:[this.data.id]}}).then(()=>{}).catch(()=>{}).finally(t=>{this.loadIng--})}}},o={};var c=l(m,n,d,!1,_,null,null,null);function _(t){for(let e in o)this[e]=o[e]}var v=function(){return c.exports}();export{v as R};
|
||||
import{m as i}from"./vuex.cc7cb26e.js";import{n as l}from"./app.84e898f6.js";var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{staticClass:"report-detail"},[a("div",{staticClass:"report-title"},[t._v(" "+t._s(t.data.title)+" "),t.loadIng>0?a("Icon",{staticClass:"icon-loading",attrs:{type:"ios-loading"}}):t._e()],1),t.formOptions.labelWidth==="auto"?a("div",{staticClass:"report-detail-context"},[a("Form",{staticClass:"report-form auto-form",attrs:{"label-width":"auto",inline:""}},[a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u4EBA")}},[a("UserAvatar",{attrs:{userid:t.data.userid,size:28}})],1),a("FormItem",{attrs:{label:t.$L("\u63D0\u4EA4\u65F6\u95F4")}},[t._v(" "+t._s(t.data.created_at)+" ")]),a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u5BF9\u8C61")}},[t.data.receives_user.length===0?[t._v("-")]:t._l(t.data.receives_user,function(r,s){return a("UserAvatar",{key:s,attrs:{userid:r.userid,size:28}})})],2)],1),a("Form",{staticClass:"report-form auto-form",attrs:{"label-width":"auto"}},[a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u5185\u5BB9")}},[a("div",{staticClass:"report-content",domProps:{innerHTML:t._s(t.data.content)}})])],1)],1):a("div",{staticClass:"report-detail-context"},[a("Form",t._b({staticClass:"report-form"},"Form",t.formOptions,!1),[t.formOptions.labelWidth!=="auto"?[a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u4EBA")}},[a("UserAvatar",{attrs:{userid:t.data.userid,size:28}})],1),a("FormItem",{attrs:{label:t.$L("\u63D0\u4EA4\u65F6\u95F4")}},[t._v(" "+t._s(t.data.created_at)+" ")]),a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u5BF9\u8C61")}},[t.data.receives_user.length===0?[t._v("-")]:t._l(t.data.receives_user,function(r,s){return a("UserAvatar",{key:s,attrs:{userid:r.userid,size:28}})})],2)]:t._e(),a("FormItem",{attrs:{label:t.$L("\u6C47\u62A5\u5185\u5BB9")}},[a("div",{staticClass:"report-content",domProps:{innerHTML:t._s(t.data.content)}})])],2)],1)])},d=[];const m={name:"ReportDetail",props:{data:{default:{}}},data(){return{loadIng:0}},computed:{...i(["formOptions"])},watch:{"data.id":{handler(t){t>0&&this.sendRead()},immediate:!0}},methods:{sendRead(){this.loadIng++,this.$store.dispatch("call",{url:"report/read",data:{ids:[this.data.id]}}).then(()=>{}).catch(()=>{}).finally(t=>{this.loadIng--})}}},o={};var c=l(m,n,d,!1,_,null,null,null);function _(t){for(let e in o)this[e]=o[e]}var v=function(){return c.exports}();export{v as R};
|
||||