Compare commits
259 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe5f56e98b | ||
|
|
40ef700e5a | ||
|
|
8661c28d10 | ||
|
|
9edddc461d | ||
|
|
2fbb640bc8 | ||
|
|
a03050bc7b | ||
|
|
654a90626e | ||
|
|
9acafed459 | ||
|
|
b7dcb543f6 | ||
|
|
e2768f7f20 | ||
|
|
cda2d0da27 | ||
|
|
c61815db3a | ||
|
|
9390965a0c | ||
|
|
0688feefb1 | ||
|
|
93c8d86caf | ||
|
|
540bff89cf | ||
|
|
41c09b3838 | ||
|
|
0a26361724 | ||
|
|
ee9ad65e18 | ||
|
|
db6b571cfb | ||
|
|
bfe359c440 | ||
|
|
ee8f67793a | ||
|
|
629fe79c61 | ||
|
|
9ae278d622 | ||
|
|
3417d68609 | ||
|
|
f757749282 | ||
|
|
ea40e95cae | ||
|
|
eb066f52fe | ||
|
|
b7007135cb | ||
|
|
a7bd403b2c | ||
|
|
59c7b148dd | ||
|
|
c67f52e960 | ||
|
|
f311625060 | ||
|
|
d3c08f8d90 | ||
|
|
2bc655d7ef | ||
|
|
d2b8d0372e | ||
|
|
40b637b16e | ||
|
|
6e68f399b4 | ||
|
|
0be6c70e92 | ||
|
|
6c2d8fc163 | ||
|
|
a8193b8feb | ||
|
|
34159caf22 | ||
|
|
c75f406459 | ||
|
|
99dca06d44 | ||
|
|
d12c0c4207 | ||
|
|
915a5ed7d5 | ||
|
|
7bfc43c85f | ||
|
|
77ea022ddf | ||
|
|
93578f93f4 | ||
|
|
f129615ebe | ||
|
|
0e5b44baad | ||
|
|
3596475790 | ||
|
|
6218521dea | ||
|
|
65db8b5703 | ||
|
|
f5ff9a3648 | ||
|
|
cbbd50a2e3 | ||
|
|
b04647e65a | ||
|
|
d34d94faa6 | ||
|
|
4038d9560f | ||
|
|
006fc43498 | ||
|
|
47c9b2e1b0 | ||
|
|
dc3e5f0a59 | ||
|
|
01bda83fcd | ||
|
|
9ecb9c68fb | ||
|
|
4612d5180a | ||
|
|
cfb653796c | ||
|
|
d00cd5cb26 | ||
|
|
285a62c87e | ||
|
|
bcb0c6bc77 | ||
|
|
d1ab2d98eb | ||
|
|
c3d5328154 | ||
|
|
fc30588014 | ||
|
|
65b02001b2 | ||
|
|
cd011a172f | ||
|
|
bf913d9eff | ||
|
|
c2dd15fca1 | ||
|
|
b267863b58 | ||
|
|
d189fb100a | ||
|
|
dc6c5bef26 | ||
|
|
7208d51644 | ||
|
|
16359a968d | ||
|
|
d553f77533 | ||
|
|
bc25f5dfdf | ||
|
|
d40028340c | ||
|
|
4194d1cddd | ||
|
|
1fdd532133 | ||
|
|
71c62a3772 | ||
|
|
9be6cd5148 | ||
|
|
c6568969c7 | ||
|
|
f5b1a6ab05 | ||
|
|
5efe659cf5 | ||
|
|
b254fd5ce2 | ||
|
|
631a0ffff4 | ||
|
|
8b11e9a19e | ||
|
|
f6b006b000 | ||
|
|
3a26f420b8 | ||
|
|
0919e415ec | ||
|
|
030a07698d | ||
|
|
a7f2582df7 | ||
|
|
5f0a0e0371 | ||
|
|
28717fd0c7 | ||
|
|
7014ea176a | ||
|
|
b4f2da66be | ||
|
|
b53462cf6e | ||
|
|
8b40364722 | ||
|
|
6ee1824410 | ||
|
|
f63c2da37a | ||
|
|
9be0642ba5 | ||
|
|
55a922c7b3 | ||
|
|
50893929d6 | ||
|
|
03c94e791a | ||
|
|
96bb554813 | ||
|
|
1bc77de144 | ||
|
|
aa07c78fc8 | ||
|
|
52dda88d40 | ||
|
|
c555b309bd | ||
|
|
0a51225762 | ||
|
|
fab49b1dda | ||
|
|
57e422f2d3 | ||
|
|
50a1a3147e | ||
|
|
277115a30f | ||
|
|
7464de3adc | ||
|
|
3d725ddeef | ||
|
|
38d8f289e4 | ||
|
|
edfd6e6de2 | ||
|
|
a68ab6512e | ||
|
|
8383b88a44 | ||
|
|
27ff24f44e | ||
|
|
b111ecb227 | ||
|
|
ac17952cd3 | ||
|
|
e24978fdd7 | ||
|
|
a4d7579e3f | ||
|
|
52171b794a | ||
|
|
3c33f02e9d | ||
|
|
0a8823c40b | ||
|
|
a3f7e71638 | ||
|
|
7ebf4fb9ce | ||
|
|
c96bad3cdf | ||
|
|
0968c43f61 | ||
|
|
ae147c76ff | ||
|
|
0e916a2804 | ||
|
|
494565e131 | ||
|
|
c4430e1a6c | ||
|
|
26adfa11bf | ||
|
|
69ec57669e | ||
|
|
3556133585 | ||
|
|
a65181757d | ||
|
|
42d39a830e | ||
|
|
2e70c9617c | ||
|
|
6230bf94c5 | ||
|
|
47832ececb | ||
|
|
60e6003485 | ||
|
|
9133f289b4 | ||
|
|
76570e2f1b | ||
|
|
c9234a4b49 | ||
|
|
c1361fadda | ||
|
|
ec7af94f71 | ||
|
|
81690d6ce9 | ||
|
|
236b57864b | ||
|
|
22259ec34d | ||
|
|
5a4700753a | ||
|
|
cc862741dc | ||
|
|
779b32e8ad | ||
|
|
e3ce3bcfbe | ||
|
|
673053f181 | ||
|
|
b6eb77ae63 | ||
|
|
0e63255a7f | ||
|
|
f42408a363 | ||
|
|
897fc51ce3 | ||
|
|
6848b126c5 | ||
|
|
0ed9afd1bd | ||
|
|
26cca8298f | ||
|
|
58407af2ba | ||
|
|
3a0473a74f | ||
|
|
6e5124fe22 | ||
|
|
02bd022c62 | ||
|
|
f2538884ea | ||
|
|
8d121d4056 | ||
|
|
96438604ee | ||
|
|
63ccd675d0 | ||
|
|
2c08145c40 | ||
|
|
12effb5738 | ||
|
|
91bfb989be | ||
|
|
192de79fea | ||
|
|
82063f1b21 | ||
|
|
02b263439b | ||
|
|
7efaf3bb32 | ||
|
|
7dd5b082cf | ||
|
|
6320eaa3ac | ||
|
|
85b88b6b61 | ||
|
|
f285665f90 | ||
|
|
8f4399dc2f | ||
|
|
c8b8cc578d | ||
|
|
a142f52113 | ||
|
|
aa666a9662 | ||
|
|
0a4ac6abb7 | ||
|
|
96b0cb8aa0 | ||
|
|
b3a30720fa | ||
|
|
b711605bdc | ||
|
|
31efee2e97 | ||
|
|
569af135bd | ||
|
|
2975a0eaf9 | ||
|
|
d4ee87f324 | ||
|
|
c676a3037c | ||
|
|
e4790062c8 | ||
|
|
bb8a6982d0 | ||
|
|
80af98111b | ||
|
|
9a69d20949 | ||
|
|
5e52996a9e | ||
|
|
33d22d4970 | ||
|
|
170473fb2d | ||
|
|
67ccaea41e | ||
|
|
67d7e81ffa | ||
|
|
1788b40431 | ||
|
|
7f432cefb9 | ||
|
|
57e8c9c7cd | ||
|
|
c1b63af5f5 | ||
|
|
cf7f245a49 | ||
|
|
4824f30950 | ||
|
|
88fb1d8e62 | ||
|
|
e67ce9a438 | ||
|
|
976b9690d2 | ||
|
|
36735ace50 | ||
|
|
3aeea13526 | ||
|
|
6f33c3f5d6 | ||
|
|
53aab1ed0f | ||
|
|
b209040978 | ||
|
|
e74aeb9393 | ||
|
|
e53242613b | ||
|
|
bea7ba00f0 | ||
|
|
24d90b93e2 | ||
|
|
f380b0433d | ||
|
|
f7df6408ed | ||
|
|
10a77ee2a9 | ||
|
|
d5db894891 | ||
|
|
5a44076859 | ||
|
|
e78513cb80 | ||
|
|
2860c4cbe6 | ||
|
|
ebce9fa596 | ||
|
|
8080d0bb4e | ||
|
|
221e42d02b | ||
|
|
e06fd21a4b | ||
|
|
f42036c104 | ||
|
|
937bc4ead3 | ||
|
|
322a855ba2 | ||
|
|
7c4d537d67 | ||
|
|
b78e4240cb | ||
|
|
4f663dd761 | ||
|
|
b3bd5aded5 | ||
|
|
7714c53085 | ||
|
|
3a74cdc98b | ||
|
|
3631f511d4 | ||
|
|
5f7d528d9d | ||
|
|
85ceb8b938 | ||
|
|
b4b268a4d7 | ||
|
|
4b39f13fa9 | ||
|
|
4abcec08f4 | ||
|
|
4144f92631 | ||
|
|
fb8d759103 |
@@ -10,6 +10,7 @@ APP_URL=http://localhost
|
||||
APP_ID=
|
||||
APP_IPPR=
|
||||
APP_PORT=2222
|
||||
APP_SSL_PORT=
|
||||
APP_DEV_PORT=
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
@@ -56,9 +57,6 @@ PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
|
||||
JUKE_KEY_JOKE=
|
||||
JUKE_KEY_SOUP=
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Publish Desktop
|
||||
name: Publish Mac
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -6,7 +6,7 @@ on:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
Build:
|
||||
runs-on: macos-latest
|
||||
environment: build
|
||||
|
||||
@@ -15,10 +15,10 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js 16.x
|
||||
- name: Use Node.js 20.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16.x
|
||||
node-version: 20.x
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
@@ -29,5 +29,6 @@ jobs:
|
||||
DP_KEY: ${{ secrets.DP_KEY }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
GH_REPOSITORY: ${{ github.repository }}
|
||||
run: ./cmd electron all
|
||||
run: |
|
||||
./cmd electron mac
|
||||
|
||||
30
.github/workflows/publish-desktop-win.yml
vendored
Normal file
30
.github/workflows/publish-desktop-win.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Publish Win
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
runs-on: windows-latest
|
||||
environment: build
|
||||
|
||||
if: startsWith(github.event.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js 20.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 20.x
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
DP_KEY: ${{ secrets.DP_KEY }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
GH_REPOSITORY: ${{ github.repository }}
|
||||
shell: bash
|
||||
run: |
|
||||
./cmd electron win
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
/node_modules
|
||||
/public/hot
|
||||
/public/tmp
|
||||
/public/summary
|
||||
/public/uploads/*
|
||||
/public/.well-known
|
||||
/public/.user.ini
|
||||
|
||||
27
.prefetch
Normal file
27
.prefetch
Normal file
@@ -0,0 +1,27 @@
|
||||
office/web-apps/apps/api/documents/api.js?hash={version}
|
||||
office/7.5.1-23/sdkjs/cell/css/main.css
|
||||
office/7.5.1-23/web-apps/apps/spreadsheeteditor/main/resources/css/app.css
|
||||
office/7.5.1-23/web-apps/vendor/requirejs/require.js
|
||||
office/7.5.1-23/web-apps/apps/spreadsheeteditor/main/app.js
|
||||
office/7.5.1-23/sdkjs/common/AllFonts.js
|
||||
office/7.5.1-23/web-apps/vendor/xregexp/xregexp-all-min.js
|
||||
office/7.5.1-23/web-apps/vendor/socketio/socket.io.min.js
|
||||
office/7.5.1-23/sdkjs/cell/sdk-all-min.js
|
||||
office/7.5.1-23/sdkjs/cell/sdk-all.js
|
||||
office/7.5.1-23/sdkjs/common/libfont/engine/fonts.js
|
||||
office/7.5.1-23/sdkjs/common/Charts/ChartStyles.js
|
||||
office/7.5.1-23/sdkjs/common/libfont/engine/fonts.wasm
|
||||
office/7.5.1-23/web-apps/apps/presentationeditor/main/resources/css/app.css
|
||||
office/7.5.1-23/web-apps/apps/presentationeditor/main/app.js
|
||||
office/7.5.1-23/sdkjs/slide/sdk-all-min.js
|
||||
office/7.5.1-23/sdkjs/slide/sdk-all.js
|
||||
office/7.5.1-23/sdkjs/slide/themes//themes.js
|
||||
office/7.5.1-23/web-apps/apps/documenteditor/main/resources/css/app.css
|
||||
office/7.5.1-23/web-apps/apps/documenteditor/main/app.js
|
||||
office/7.5.1-23/sdkjs/word/sdk-all-min.js
|
||||
office/7.5.1-23/sdkjs/word/sdk-all.js
|
||||
drawio/webapp/js/app.min.js
|
||||
drawio/webapp/js/stencils.min.js
|
||||
drawio/webapp/js/extensions.min.js
|
||||
drawio/webapp/js/shapes-14-6-5.min.js
|
||||
drawio/webapp/math/es5/output/svg/fonts/tex.js
|
||||
342
CHANGELOG.md
342
CHANGELOG.md
@@ -2,6 +2,315 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.36.60]
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化使用默认浏览器打开规则
|
||||
- 优化聊天图片上传
|
||||
- 临时帐号别名
|
||||
- Tab icon load error
|
||||
- 优化会议
|
||||
- 创建会议不需要加入机器人
|
||||
- 暗黑模式下窗口背景色兼容问题
|
||||
- 优化网络检查
|
||||
- 客户端会议优化
|
||||
|
||||
## [0.36.49]
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化会议室
|
||||
|
||||
## [0.36.44]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 部分情况出现注册失败
|
||||
- 最小化阅读窗口新建窗口不自动激活
|
||||
- 独立窗口不更新消息
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化数据读取机制
|
||||
- 优化缓存规则
|
||||
- 优化完成待办数据推送
|
||||
- 评论审批图片和投票深色按钮
|
||||
|
||||
## [0.36.36]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 修改回复、转发消息后引用的部分消失
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化任务日志内容
|
||||
- 查看版本免请求接口
|
||||
- 添加任务时选择任务位置内容溢出
|
||||
- 消息支持style
|
||||
- 回复消息列表隐藏顶部loading
|
||||
- 支持FCM推送
|
||||
- 设置华为推送自分类
|
||||
- 优化添加任务可见性点击效果
|
||||
|
||||
## [0.36.26]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 关闭文件后无法再次打开
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化数据结构
|
||||
- 接龙优化为清空内容默认删除
|
||||
- 支持取消发送中的消息
|
||||
- 1. 强化接龙接口本地时间戳问题 2. 接龙消息点展开按钮后做缓存处理
|
||||
|
||||
## [0.36.15]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 消息太长导致菜单无法正常显示
|
||||
- 项目数量不正确的情况
|
||||
- 部分未读和待办信息不显示的情况
|
||||
- 审批中心修复loadIng效果
|
||||
|
||||
### Performance
|
||||
|
||||
- 自动识别md格式发送
|
||||
- 优化回复、转发消息数据结构
|
||||
- 优化iOS端数据读取失败的情况
|
||||
- 回复消息时自动@提及
|
||||
- 优化会话数据结构
|
||||
|
||||
## [0.35.90]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 子窗口出现重新登录的情况
|
||||
|
||||
### Performance
|
||||
|
||||
- 聊天文件发送进度
|
||||
- 拨打电话确认提示
|
||||
- 优化预加载文件
|
||||
|
||||
## [0.35.84]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 回复消息点击到原文无效
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化接口时间
|
||||
- 优化审批对话按钮配色
|
||||
|
||||
## [0.35.76]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 客户端无法打开excel文件
|
||||
- 修复投票实名逻辑
|
||||
|
||||
### Features
|
||||
|
||||
- 升级okr
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化文件功能按钮
|
||||
- 文件上传支持覆盖上传
|
||||
- 优化app等比显示
|
||||
- 优化发送文件预览
|
||||
- 消息发送中禁止右键菜单
|
||||
- 部分搜索框图标抖动
|
||||
- 优化复制功能
|
||||
- 优化pdf文件预览
|
||||
- 优化投票接口,加上事务锁
|
||||
- 优化接龙接口,加上事务锁
|
||||
- 优化转发消息样式
|
||||
- 接龙接口-强化排序
|
||||
- 审批按钮色微调
|
||||
- 统一审批中心的按钮色
|
||||
- 转发会议亮色皮肤问题,转发文件宽度铺满
|
||||
- 优化app数据交互
|
||||
|
||||
### Styling
|
||||
|
||||
- 调整代码格式
|
||||
|
||||
## [0.35.48]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 修复搜索偶尔无效的情况
|
||||
|
||||
### Features
|
||||
|
||||
- 升级okr
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化文件预览
|
||||
- 滑动列表自动隐藏键盘
|
||||
- 优化时间格式
|
||||
- 适配nodejs 20
|
||||
|
||||
## [0.35.40]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 部分手机出现非正常滚动到底部的情况
|
||||
- Dootask官网标题
|
||||
- Dootask官网调整
|
||||
- 修复导出任务统计没有按创建时间来的bug
|
||||
|
||||
### Features
|
||||
|
||||
- 新增不显示会话功能
|
||||
- 升级okr
|
||||
|
||||
### Performance
|
||||
|
||||
- 修改消息换行优化
|
||||
- 优化预加载资源
|
||||
- 优化pdf文件预览
|
||||
- 优化签到消息
|
||||
- 优化登录
|
||||
- 优化安装脚本
|
||||
- 优化消息时间格式
|
||||
- 优化app功能
|
||||
|
||||
## [0.35.20]
|
||||
|
||||
### Features
|
||||
|
||||
- 发起投票功能添加缓存记录选中效果
|
||||
- 导出的签到数据和审批数据换成xlsx,因老版本的xls会出现兼容性问题
|
||||
|
||||
### Performance
|
||||
|
||||
- 默认映射443端口
|
||||
- 优化子窗口
|
||||
- 优化发布接口 删除目录的逻辑
|
||||
|
||||
## [0.35.10]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 修改消息导致最后消息改变
|
||||
- 显示无关系的子任务、指定成员可见消息推送
|
||||
- 调整gemini机器人设置参数
|
||||
|
||||
### Performance
|
||||
|
||||
- 更新说明文档
|
||||
- 优化客户端
|
||||
- 默认关闭端到端加密传输
|
||||
|
||||
## [0.34.95]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 调整发送参数逻辑
|
||||
- 推送标题存在换行时不显示
|
||||
- 修复下载文件大小为0时报错
|
||||
- 更改其他版本的链接
|
||||
- 修复价格页面样式
|
||||
- 发布接口,调整缓存时间为两小时
|
||||
- 修复okr定时处理信息不发送
|
||||
- 项目已归档,任务面板也没有这三个任务,但是每次新增报告,都会弹任务出来
|
||||
- 修改下载页面按钮布局样式
|
||||
|
||||
### Features
|
||||
|
||||
- 升级okr
|
||||
- 优化内置浏览器
|
||||
- Gemini机器人添加代理参数
|
||||
- 发布接口只保留最近两个版本
|
||||
- 官网添加其他版本的按钮
|
||||
- 统一表为utf8mb4_unicode_ci
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化ai机器人
|
||||
- Okr和审批优化
|
||||
- 优化pdf在线预览
|
||||
- 优化客户端打开服务器链接
|
||||
- 签到设置,有些客户服务器安全体系会拦截 curl -sSL 关键字,优化为cmd不传值
|
||||
- 签到设置,有些客户服务器安全体系会拦截 curl -sSL 关键字,优化为base64返回
|
||||
|
||||
## [0.34.66]
|
||||
|
||||
### Performance
|
||||
|
||||
- 升级okr容器
|
||||
- 新增禁止私聊、群聊功能
|
||||
- 更换笑话和鸡汤接口
|
||||
|
||||
## [0.34.59]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 部分机型首次打开聊天窗口不显示聊天记录的问题
|
||||
|
||||
### Performance
|
||||
|
||||
- 修复一些问题
|
||||
- IOS打开键盘时看不见通知的情况
|
||||
- 优化系统参数
|
||||
- 优化菜单显示位置
|
||||
- 优化获取最近消息
|
||||
- 优化请求时间
|
||||
- 优化触摸长按和右键菜单共存
|
||||
|
||||
## [0.34.46]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 重复通知
|
||||
- 修复投票进度的算法
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化发送消息接口
|
||||
- 优化搜索提示
|
||||
- 优化消息列表
|
||||
- 优化消息保存覆盖
|
||||
- 优化快捷表情发送消息时关闭延迟的问题
|
||||
- 升级okr
|
||||
|
||||
## [0.34.28]
|
||||
|
||||
### Features
|
||||
|
||||
- 更新okr
|
||||
- 添加年度报告接口
|
||||
|
||||
### Performance
|
||||
|
||||
- 年度报告接口 - 查询条件优化
|
||||
- 升级okr, ai
|
||||
- 年度汇报接口返回用户头像
|
||||
- 年度报告接口 - 增加用户信息字段返回
|
||||
- 去掉未使用的引用
|
||||
- 优化滑动返回动画效果
|
||||
- 消息置顶滚动恢复
|
||||
- 优化消息Load效果
|
||||
|
||||
## [0.33.98]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 消息阅读回馈
|
||||
|
||||
### Performance
|
||||
|
||||
- 消息首次加载数据优化
|
||||
- 优化打包下载
|
||||
|
||||
## [0.33.91]
|
||||
|
||||
### Bug Fixes
|
||||
@@ -17,15 +326,12 @@ All notable changes to this project will be documented in this file.
|
||||
- 优化报告未读接口
|
||||
- 优化图片显示
|
||||
- 优化代码
|
||||
- 优化代码
|
||||
- 代码整理
|
||||
- 优化待审批流程数量接口
|
||||
- 代码优化
|
||||
- 优化未读消息提示
|
||||
- 优化预览消息
|
||||
- 优化缓存数据
|
||||
- 代码优化
|
||||
- 代码整理
|
||||
- 任务可见性用户 - 分表优化
|
||||
- 代码命名优化
|
||||
- 移动任务后,对应项目路径也要更改显示
|
||||
@@ -59,13 +365,11 @@ All notable changes to this project will be documented in this file.
|
||||
- 优化未读消息提示动画
|
||||
- 优化消息更新机制
|
||||
- 优化缓存
|
||||
- 优化用户选择器
|
||||
|
||||
## [0.33.41]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 更新导致的小问题
|
||||
- 更新导致的小问题
|
||||
|
||||
### Performance
|
||||
@@ -98,7 +402,6 @@ All notable changes to this project will be documented in this file.
|
||||
- Okr版本升级
|
||||
- 1.数据库迁移文件修复 2.转发样式优化
|
||||
- 兼容okr1.1版本
|
||||
- 兼容okr1.1版本
|
||||
- 整体数据库索引和字段类型优化
|
||||
- 项目列表数据库查询优化
|
||||
|
||||
@@ -173,7 +476,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 添加一个 @我的 消息标签
|
||||
- 转发消息 - 添加单选模式
|
||||
- 转发消息 - 添加来源显示
|
||||
- 翻译
|
||||
- 首页改版 - 100%
|
||||
- 新增项目任务创建权限功能 - 90%
|
||||
- 更换calendar
|
||||
@@ -183,10 +485,8 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- 优化消息阅读逻辑
|
||||
- 微应用优化
|
||||
- 微应用优化
|
||||
- 优化未读消息机制
|
||||
- 优化重连时消息列表跳回第一页的情况
|
||||
- 优化未读消息机制
|
||||
- 优化消息更新太快导致不更新数据的情况
|
||||
- 机器人添加清空上下文菜单
|
||||
- 优化翻译
|
||||
@@ -195,22 +495,16 @@ All notable changes to this project will be documented in this file.
|
||||
- 优化扫一扫登录功能
|
||||
- 优化头像
|
||||
- 兼容okr1.1版本
|
||||
- 兼容okr1.1版本
|
||||
- 兼容okr1.1版本
|
||||
- 接龙和投票的样式优化
|
||||
- 逻辑强化
|
||||
- 未读消息优化
|
||||
- 搜索消息时按esc取消搜索
|
||||
- 接龙优化
|
||||
- 接龙优化
|
||||
- 移动设备优化消息输入框菜单
|
||||
- 优化消息输入框@所有人暗黑样式
|
||||
- 优化@人名换行的情况
|
||||
- 样式优化
|
||||
- 优化导出任务统计
|
||||
- 样式调优
|
||||
- 客户端下载按钮,仪表盘不显示
|
||||
- 未读消息优化
|
||||
- 细节优化
|
||||
|
||||
## [0.32.17]
|
||||
@@ -219,7 +513,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- 修复打包下载问题
|
||||
- 1. 修复 windows端 右键发送 是直接发送了,没有出现使用md格式发送 2.其他bug修复
|
||||
- 修复打包下载问题
|
||||
- 修复统一打包下载命名
|
||||
|
||||
### Features
|
||||
@@ -258,7 +551,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 文件共享只读禁止下载文件
|
||||
- 保存任务详情至文件的方法 添加失败日志
|
||||
- 翻译
|
||||
- 翻译
|
||||
- 新增实现文件夹下载以及多文件压缩下载功能
|
||||
- 任务可以筛选未设置时间的
|
||||
- 临时账号可以主动跟机器人聊天
|
||||
@@ -267,14 +559,11 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- Office只读模式,隐藏下载按钮
|
||||
- 优化实现文件夹下载以及多文件压缩下载功能
|
||||
- 优化实现文件夹下载以及多文件压缩下载功能
|
||||
- 机器人设置页面,点点点看不到内容,需要给弹窗看详细内容
|
||||
- 文件选中后,移动端页面宽度放不下对应内容
|
||||
- 文件选中后,移动端页面宽度放不下对应内容,没有滚动条
|
||||
- 压缩下载改名打包下载
|
||||
- 复制链接去除主题语言参数
|
||||
- 优化实现文件夹下载以及多文件压缩下载功能
|
||||
- 优化实现文件夹下载以及多文件压缩下载功能
|
||||
|
||||
## [0.31.75]
|
||||
|
||||
@@ -416,14 +705,12 @@ All notable changes to this project will be documented in this file.
|
||||
- 去掉test信息
|
||||
- 按照dootask启动原始尺寸截取使用说明的图
|
||||
- 修改边栏目录滚动效果
|
||||
- 修改边栏目录滚动效果
|
||||
- 官网使用说明的图重新截取更换
|
||||
- 优化官网布局与样式
|
||||
- 修复下载英文页面跳转
|
||||
|
||||
### Features
|
||||
|
||||
- 新增创建聊天关联id
|
||||
- 新增创建聊天关联id
|
||||
- Okr信息面板新增"打开OKR"按钮
|
||||
- 新增OKR信息推送
|
||||
@@ -510,7 +797,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 优化会员选择器
|
||||
- 优化图片压缩
|
||||
- 回复图片显示图片搜略图
|
||||
- 优化会员选择器
|
||||
- 会员选择下拉框提示
|
||||
|
||||
## [0.27.26]
|
||||
@@ -541,7 +827,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- 修复获取聊天列表的接口
|
||||
- 添加密码账号长度限制
|
||||
- 添加密码账号长度限制
|
||||
- Dootask对接系统分享 - 添加头像返回
|
||||
- 兼容加密bug问题处理
|
||||
- Dootask对接系统分享
|
||||
@@ -591,7 +876,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 审批流程静态页
|
||||
- 审批流程静态页
|
||||
|
||||
### Performance
|
||||
@@ -1876,7 +2160,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 优化甘特图
|
||||
- 优化任务列表切换显示
|
||||
- 更新icon图标库
|
||||
- 更新icon图标库
|
||||
- 已删除任务详情任务描述改为只读
|
||||
- 已删除任务操作文案及显示优化
|
||||
- 项目--删除任务查看详情页功能
|
||||
@@ -1967,7 +2250,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 报表导出任务没有流程日志判断优化
|
||||
- 修复登录页设置下拉显示不全的情况
|
||||
- 处理回滚后异常代码
|
||||
- 处理回滚后异常代码
|
||||
- 【系统设置】邮件设置提前小时数双向绑定无效问题修改
|
||||
|
||||
### Features
|
||||
@@ -2055,7 +2337,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 调整消息置顶标识位置
|
||||
- 消息列表详情增加'置顶'标识
|
||||
- 项目列表置顶优化
|
||||
- 项目列表置顶优化
|
||||
- 【文件】剪切后加'取消剪切'按钮
|
||||
- 消息会话右键时隐藏滚动条
|
||||
- 页面高度足够时只滚动项目部分
|
||||
@@ -2156,7 +2437,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 该文件版本已经改变了。该页面将被重新加载
|
||||
- 点击切换语言一级菜单出现的兼容问题
|
||||
- 上传文件夹
|
||||
- 该文件版本已经改变了。该页面将被重新加载
|
||||
- 团队管理新增身份筛选项
|
||||
- 任务文件支持更多格式上传
|
||||
|
||||
@@ -2194,7 +2474,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 任务中没有聊天记录时,发送图片无法成功
|
||||
- 修复消息撤回文字提示在第一条时会被顶部遮住的问题
|
||||
- 修复个人对话为空时无法重复打开该对话的问题
|
||||
- 修复消息撤回文字提示在第一条时会被顶部遮住的问题
|
||||
- MacOS客户端首次不加载角标的问题
|
||||
- 工作流列表接口用作筛选时不用传多余参数
|
||||
|
||||
@@ -2295,7 +2574,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- 工作报告优化
|
||||
- 规范代码
|
||||
- 工作报告优化
|
||||
- 共享文件删除、移动改为仅限所有者或创建者操作
|
||||
|
||||
## [0.6.38]
|
||||
@@ -2575,7 +2853,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
### Performance
|
||||
|
||||
- 客户端新窗口打开文件
|
||||
- 客户端窗口标题
|
||||
- 领取任务流程
|
||||
- 到期时间格式化
|
||||
@@ -2588,7 +2865,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- 客户端文件窗口样式
|
||||
- Iview
|
||||
- Iview
|
||||
- 排序箭头颜色
|
||||
|
||||
## [0.4.28]
|
||||
|
||||
32
README.md
32
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
English | **[中文文档](./README_CN.md)**
|
||||
|
||||
- [Screenshot Preview](README_PREVIEW.md)
|
||||
- [Screenshot preview](./README_PREVIEW.md)
|
||||
- [Demo site](http://www.dootask.com/)
|
||||
|
||||
**QQ Group**
|
||||
@@ -12,8 +12,9 @@ Group No.: `546574618`
|
||||
## Setup
|
||||
|
||||
- `Docker v20.10+` & `Docker Compose v2.0+` must be installed
|
||||
- System: `Centos/Debian/Ubuntu/macOS`
|
||||
- System: `Centos/Debian/Ubuntu/macOS/Windows`
|
||||
- Hardware suggestion: 2 cores and above 4G memory
|
||||
- Special note: Windows users please use `git bash` or `cmder` to run the command
|
||||
|
||||
### Deployment (Pro Edition)
|
||||
|
||||
@@ -28,7 +29,7 @@ git clone -b pro --depth=1 https://gitee.com/aipaw/dootask.git
|
||||
# 2、Enter directory
|
||||
cd dootask
|
||||
|
||||
# 3、Installation(Custom port installation: ./cmd install --port 2222)
|
||||
# 3、Installation(Custom port installation, as: ./cmd install --port 80)
|
||||
./cmd install
|
||||
```
|
||||
|
||||
@@ -42,7 +43,8 @@ cd dootask
|
||||
### Change port
|
||||
|
||||
```bash
|
||||
./cmd port 2222
|
||||
# This method only replaces the HTTP port. To replace the HTTPS port, please read the SSL configuration below
|
||||
./cmd port 80
|
||||
```
|
||||
|
||||
### Change App Url
|
||||
@@ -66,11 +68,13 @@ cd dootask
|
||||
|
||||
### Development compilation
|
||||
|
||||
- `NodeJs 20+` must be installed
|
||||
|
||||
```bash
|
||||
# Development mode, Mac OS only
|
||||
# Development
|
||||
./cmd dev
|
||||
|
||||
# Production projects, macOS only
|
||||
# Production (This is web client. For App/PC/Mac clients, Please read README-CLIENT.md)
|
||||
./cmd prod
|
||||
```
|
||||
|
||||
@@ -84,11 +88,19 @@ cd dootask
|
||||
./cmd redis "your command" # To run a redis command
|
||||
./cmd composer "your command" # To run a composer command
|
||||
./cmd supervisorctl "your command" # To run a supervisorctl command
|
||||
./cmd test "your command" # To run a phpunit command
|
||||
./cmd mysql "your command" # To run a mysql command (backup: Backup database, recovery: Restore database)
|
||||
```
|
||||
|
||||
### NGINX PROXY SSL
|
||||
### SSL configuration
|
||||
|
||||
#### Method 1: Automatic configuration
|
||||
|
||||
```bash
|
||||
# Running commands in a project
|
||||
./cmd https
|
||||
```
|
||||
|
||||
#### Or Method 2: Nginx Agent Configuration
|
||||
|
||||
```bash
|
||||
# 1、Nginx config add
|
||||
@@ -96,8 +108,8 @@ proxy_set_header X-Forwarded-Host $http_host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
# 2、Running commands in a project
|
||||
./cmd https
|
||||
# 2、Running commands in a project (If you unconfigure the NGINX agent, run: ./cmd https close)
|
||||
./cmd https agent
|
||||
```
|
||||
|
||||
## Upgrade
|
||||
|
||||
@@ -3,19 +3,23 @@
|
||||
## 1、App客户端
|
||||
|
||||
#### 1.1、说明
|
||||
|
||||
目录 `resources/mobile`,使用`eeui.app`框架,遵从eeui的开发文档进行打包开发app
|
||||
|
||||
#### 1.2、编译App
|
||||
1. 在项目目录执行 `./cmd appbuild` 编译
|
||||
|
||||
1. 在项目目录执行 `./cmd appbuild [build|setting]` 编译
|
||||
2. 进入 `resources/mobile` eeui框架内打包Android或iOS应用
|
||||
|
||||
|
||||
## 2、PC/Mac客户端
|
||||
|
||||
#### 2.1、说明
|
||||
|
||||
目录 `electron`,使用`electron`框架,遵从electron的开发文档进行打包客户端
|
||||
|
||||
#### 2.2、编译客户端
|
||||
在项目目录执行 `./cmd electron` 根据提示编译
|
||||
|
||||
在项目目录执行 `./cmd electron [dev]` 根据提示编译
|
||||
|
||||
|
||||
|
||||
32
README_CN.md
32
README_CN.md
@@ -2,7 +2,7 @@
|
||||
|
||||
**[English](./README.md)** | 中文文档
|
||||
|
||||
- [截图预览](README_PREVIEW.md)
|
||||
- [截图预览](./README_PREVIEW.md)
|
||||
- [演示站点](http://www.dootask.com/)
|
||||
|
||||
**QQ交流群**
|
||||
@@ -12,8 +12,9 @@
|
||||
## 安装程序
|
||||
|
||||
- 必须安装:`Docker v20.10+` 和 `Docker Compose v2.0+`
|
||||
- 支持环境:`Centos/Debian/Ubuntu/macOS`
|
||||
- 支持环境:`Centos/Debian/Ubuntu/macOS/Windows`
|
||||
- 硬件建议:2核4G以上
|
||||
- 特别说明:Windows 用户请使用 `git bash` 或者 `cmder` 运行命令
|
||||
|
||||
### 部署项目(Pro版)
|
||||
|
||||
@@ -28,7 +29,7 @@ git clone -b pro --depth=1 https://gitee.com/aipaw/dootask.git
|
||||
# 2、进入目录
|
||||
cd dootask
|
||||
|
||||
# 3、一键安装项目(自定义端口安装 ./cmd install --port 2222)
|
||||
# 3、一键安装项目(自定义端口安装,如:./cmd install --port 80)
|
||||
./cmd install
|
||||
```
|
||||
|
||||
@@ -42,7 +43,8 @@ cd dootask
|
||||
### 更换端口
|
||||
|
||||
```bash
|
||||
./cmd port 2222
|
||||
# 此方法仅更换http端口,更换https端口请阅读下面SSL配置
|
||||
./cmd port 80
|
||||
```
|
||||
|
||||
### 更换URL
|
||||
@@ -66,11 +68,13 @@ cd dootask
|
||||
|
||||
### 开发编译
|
||||
|
||||
- 请确保你已经安装了 `NodeJs 20+`
|
||||
|
||||
```bash
|
||||
# 开发模式,仅限macOS
|
||||
# 开发模式
|
||||
./cmd dev
|
||||
|
||||
# 编译项目,仅限macOS
|
||||
# 编译项目(这是网页端的,App/Pc/Mac客户端请查看 README_CLIENT.md)
|
||||
./cmd prod
|
||||
```
|
||||
|
||||
@@ -85,11 +89,19 @@ cd dootask
|
||||
./cmd redis "your command" # 运行 redis 命令
|
||||
./cmd composer "your command" # 运行 composer 命令
|
||||
./cmd supervisorctl "your command" # 运行 supervisorctl 命令
|
||||
./cmd test "your command" # 运行 phpunit 命令
|
||||
./cmd mysql "your command" # 运行 mysql 命令 (backup: 备份数据库,recovery: 还原数据库)
|
||||
```
|
||||
|
||||
### NGINX 代理 SSL
|
||||
### SSL 配置
|
||||
|
||||
#### 方法1:自动配置
|
||||
|
||||
```bash
|
||||
# 在项目下运行命令,根据提示执行即可
|
||||
./cmd https
|
||||
```
|
||||
|
||||
#### (或者)方法2:Nginx 代理配置
|
||||
|
||||
```bash
|
||||
# 1、Nginx 代理配置添加
|
||||
@@ -97,8 +109,8 @@ proxy_set_header X-Forwarded-Host $http_host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
# 2、在项目下运行命令
|
||||
./cmd https
|
||||
# 2、在项目下运行命令(如果取消 Nginx 代理配置请运行:./cmd https close)
|
||||
./cmd https agent
|
||||
```
|
||||
|
||||
## 升级更新
|
||||
|
||||
@@ -22,5 +22,5 @@
|
||||
|
||||
## 编译App
|
||||
|
||||
1. 执行 `./cmd appbuild` 或 `./cmd appbuild setting` 编译
|
||||
1. 执行 `./cmd appbuild [setting]` 编译
|
||||
2. 进入 `resources/mobile` eeui框架内打包Android或iOS应用
|
||||
|
||||
@@ -207,7 +207,7 @@ class ApproveController extends AbstractController
|
||||
if ($id != $user->userid) {
|
||||
$dialog = WebSocketDialog::checkUserDialog($botUser, $id);
|
||||
$processInst['comment_user_id'] = $user->userid;
|
||||
$processInst['comment_content'] = json_decode($data['content'], true)['content'];
|
||||
$processInst['comment_contents'] = json_decode($data['content'], true) ?? [];
|
||||
$this->approveMsg('approve_comment_notifier', $dialog, $botUser, $processInst, $processInst);
|
||||
}
|
||||
}
|
||||
@@ -858,7 +858,7 @@ class ApproveController extends AbstractController
|
||||
BillExport::create()->setTitle($title)->setHeadings($headings)->setData($datas)->setStyles(["A1:Y1" => ["font" => ["bold" => true]]])
|
||||
];
|
||||
//
|
||||
$fileName = '审批记录_' . Base::time() . '.xls';
|
||||
$fileName = '审批记录_' . Base::time() . '.xlsx';
|
||||
$filePath = "temp/approve/export/" . date("Ym", Base::time());
|
||||
$export = new BillMultipleExport($sheets);
|
||||
$res = $export->store($filePath . "/" . $fileName);
|
||||
@@ -866,7 +866,7 @@ class ApproveController extends AbstractController
|
||||
return Base::retError('导出失败,' . $fileName . '!');
|
||||
}
|
||||
$xlsPath = storage_path("app/" . $filePath . "/" . $fileName);
|
||||
$zipFile = "app/" . $filePath . "/" . Base::rightDelete($fileName, '.xls') . ".zip";
|
||||
$zipFile = "app/" . $filePath . "/" . Base::rightDelete($fileName, '.xlsx') . ".zip";
|
||||
$zipPath = storage_path($zipFile);
|
||||
if (file_exists($zipPath)) {
|
||||
Base::deleteDirAndFile($zipPath, true);
|
||||
@@ -983,7 +983,8 @@ class ApproveController extends AbstractController
|
||||
'end_day_of_week' => '周' . Base::getTimeWeek(Carbon::parse($process['var']['end_time'])->timestamp),
|
||||
'description' => $process['var']['description'],
|
||||
'comment_nickname' => $process['comment_user_id'] ? User::userid2nickname($process['comment_user_id']) : '',
|
||||
'comment_content' => $process['comment_content'] ?? ''
|
||||
'comment_content' => $process['comment_contents']['content'] ?? '',
|
||||
'comment_pictures' => $process['comment_contents']['pictures'] ?? []
|
||||
];
|
||||
$text = view('push.bot', ['type' => $type, 'action' => $action, 'is_finished' => $process['is_finished'], 'data' => (object)$data])->render();
|
||||
$text = preg_replace("/^\x20+/", "", $text);
|
||||
@@ -995,7 +996,7 @@ class ApproveController extends AbstractController
|
||||
return WebSocketDialogMsg::sendMsg($msg_action, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||
}
|
||||
// 查找最后一条消息msg_id
|
||||
$msg_action = 'update-' . $toUser['msg_id'];
|
||||
$msg_action = 'change-' . $toUser['msg_id'];
|
||||
}
|
||||
//
|
||||
try {
|
||||
|
||||
@@ -58,29 +58,36 @@ class DialogController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/unread 02. 未读对话列表
|
||||
* @api {get} api/dialog/beyond 02. 列表外对话
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiDescription 需要token身份,列表外的未读对话 和 列表外的待办对话
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName lists
|
||||
* @apiName beyond
|
||||
*
|
||||
* @apiParam {String} before_at 在这个时间之前未读的数据
|
||||
* @apiParam {String} unread_at 在这个时间之前未读的数据
|
||||
* - 格式1:2021-01-01 00:00:00
|
||||
* - 格式2:1612051200
|
||||
* @apiParam {String} todo_at 在这个时间之前待办的数据
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function unread()
|
||||
public function beyond()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$beforeAt = Request::input('before_at');
|
||||
if (empty($beforeAt)) {
|
||||
return Base::retError('参数错误');
|
||||
}
|
||||
$unreadAt = Request::input('unread_at');
|
||||
$todoAt = Request::input('todo_at');
|
||||
//
|
||||
$data = WebSocketDialog::getDialogUnread($user->userid, Carbon::parse($beforeAt));
|
||||
$unreadAt = Base::isNumber($unreadAt) ? intval($unreadAt) : trim($unreadAt);
|
||||
$unreadAt = Carbon::parse($unreadAt)->setTimezone(config('app.timezone'));
|
||||
//
|
||||
$todoAt = Base::isNumber($todoAt) ? intval($todoAt) : trim($todoAt);
|
||||
$todoAt = Carbon::parse($todoAt)->setTimezone(config('app.timezone'));
|
||||
//
|
||||
$data = WebSocketDialog::getDialogBeyond($user->userid, $unreadAt, $todoAt);
|
||||
//
|
||||
return Base::retSuccess('success', $data);
|
||||
}
|
||||
@@ -108,12 +115,12 @@ class DialogController extends AbstractController
|
||||
return Base::retError('请输入搜索关键词');
|
||||
}
|
||||
// 搜索会话
|
||||
$dialogs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.color', 'u.updated_at as user_at'])
|
||||
$dialogs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->where('web_socket_dialogs.name', 'LIKE', "%{$key}%")
|
||||
->where('u.userid', $user->userid)
|
||||
->orderByDesc('u.top_at')
|
||||
->orderByDesc('web_socket_dialogs.last_at')
|
||||
->orderByDesc('u.last_at')
|
||||
->take(20)
|
||||
->get();
|
||||
$dialogs->transform(function (WebSocketDialog $item) use ($user) {
|
||||
@@ -145,7 +152,7 @@ class DialogController extends AbstractController
|
||||
}
|
||||
// 搜索消息会话
|
||||
if (count($list) < 20) {
|
||||
$msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
|
||||
$msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->join('web_socket_dialog_msgs as m', 'web_socket_dialogs.id', '=', 'm.dialog_id')
|
||||
->where('u.userid', $user->userid)
|
||||
@@ -178,7 +185,7 @@ class DialogController extends AbstractController
|
||||
{
|
||||
$user = User::auth();
|
||||
// 搜索会话
|
||||
$msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
|
||||
$msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->join('web_socket_dialog_msgs as m', 'web_socket_dialogs.id', '=', 'm.dialog_id')
|
||||
->where('u.userid', $user->userid)
|
||||
@@ -213,7 +220,7 @@ class DialogController extends AbstractController
|
||||
//
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
//
|
||||
$item = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.color', 'u.updated_at as user_at'])
|
||||
$item = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->where('web_socket_dialogs.id', $dialog_id)
|
||||
->where('u.userid', $user->userid)
|
||||
@@ -249,8 +256,8 @@ class DialogController extends AbstractController
|
||||
//
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id);
|
||||
//
|
||||
$data = $dialog->dialogUser->toArray();
|
||||
if ($getuser === 1) {
|
||||
$data = $dialog->dialogUser->toArray();
|
||||
$array = [];
|
||||
foreach ($data as $item) {
|
||||
$res = User::userid2basic($item['userid']);
|
||||
@@ -258,14 +265,16 @@ class DialogController extends AbstractController
|
||||
$array[] = array_merge($item, $res->toArray());
|
||||
}
|
||||
}
|
||||
$data = $array;
|
||||
}
|
||||
//
|
||||
$array = [];
|
||||
foreach ($data as $item) {
|
||||
if ($item['userid'] > 0) {
|
||||
$array[] = $item;
|
||||
}
|
||||
$array = array_filter($array, function ($item) {
|
||||
return $item['userid'] > 0;
|
||||
});
|
||||
} else {
|
||||
$data = WebSocketDialogUser::select(['web_socket_dialog_users.*', 'users.bot'])
|
||||
->join('users', 'web_socket_dialog_users.userid', '=', 'users.userid')
|
||||
->where('web_socket_dialog_users.dialog_id', $dialog_id)
|
||||
->orderBy('web_socket_dialog_users.id')
|
||||
->get();
|
||||
$array = $data->toArray();
|
||||
}
|
||||
return Base::retSuccess('success', $array);
|
||||
}
|
||||
@@ -330,6 +339,41 @@ class DialogController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/hide 08. 会话隐藏
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName hide
|
||||
*
|
||||
* @apiParam {Number} dialog_id 会话ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function hide()
|
||||
{
|
||||
$user = User::auth();
|
||||
$dialogId = intval(Request::input('dialog_id'));
|
||||
$dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
|
||||
if (!$dialogUser) {
|
||||
return Base::retError("会话不存在");
|
||||
}
|
||||
if ($dialogUser->top_at) {
|
||||
return Base::retError("置顶会话无法隐藏");
|
||||
}
|
||||
$dialogUser->hide = 1;
|
||||
$dialogUser->save();
|
||||
return Base::retSuccess("success", [
|
||||
'id' => $dialogUser->dialog_id,
|
||||
'hide' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/tel 09. 获取对方联系电话
|
||||
*
|
||||
@@ -553,10 +597,9 @@ class DialogController extends AbstractController
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__latest
|
||||
*
|
||||
* @apiParam {Number} [latest_id] 此消息ID之后的数据
|
||||
*
|
||||
* @apiParam {Number} [page] 当前页,默认:1
|
||||
* @apiParam {Number} [pagesize] 每页显示数量,默认:50,最大:100
|
||||
* @apiParam {Array} [dialogs] 对话ID列表
|
||||
* - 格式:[{id:会话ID, latest_id:此消息ID之后的数据}, ...]
|
||||
* @apiParam {Number} [take] 每个会话获取多少条,默认:25,最大:50
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@@ -564,26 +607,51 @@ class DialogController extends AbstractController
|
||||
*/
|
||||
public function msg__latest()
|
||||
{
|
||||
if (!Base::judgeClientVersion('0.34.47')) {
|
||||
return Base::retSuccess('success', ['data' => []]);
|
||||
}
|
||||
//
|
||||
$user = User::auth();
|
||||
//
|
||||
$latest_id = intval(Request::input('latest_id'));
|
||||
//
|
||||
$dialogs = Request::input('dialogs');
|
||||
if (empty($dialogs) || !is_array($dialogs)) {
|
||||
return Base::retError('参数错误');
|
||||
}
|
||||
$builder = WebSocketDialogMsg::select([
|
||||
'web_socket_dialog_msgs.*',
|
||||
'read.mention',
|
||||
'read.read_at',
|
||||
])->join('web_socket_dialog_msg_reads as read', 'read.msg_id', '=', 'web_socket_dialog_msgs.id')
|
||||
->where('read.userid', $user->userid);
|
||||
//
|
||||
if ($latest_id > 0) {
|
||||
$builder->where('read.msg_id', '>', $latest_id);
|
||||
])->leftJoin('web_socket_dialog_msg_reads as read', function ($leftJoin) use ($user) {
|
||||
$leftJoin
|
||||
->on('read.userid', '=', DB::raw($user->userid))
|
||||
->on('read.msg_id', '=', 'web_socket_dialog_msgs.id');
|
||||
});
|
||||
$data = [];
|
||||
$num = 0;
|
||||
foreach ($dialogs as $item) {
|
||||
$dialog_id = intval($item['id']);
|
||||
$latest_id = intval($item['latest_id']);
|
||||
if ($dialog_id <= 0) {
|
||||
continue;
|
||||
}
|
||||
if ($num >= 5) {
|
||||
break;
|
||||
}
|
||||
$num++;
|
||||
WebSocketDialog::checkDialog($dialog_id);
|
||||
//
|
||||
$cloner = $builder->clone();
|
||||
$cloner->where('web_socket_dialog_msgs.dialog_id', $dialog_id);
|
||||
if ($latest_id > 0) {
|
||||
$cloner->where('web_socket_dialog_msgs.id', '>', $latest_id);
|
||||
}
|
||||
$cloner->orderByDesc('web_socket_dialog_msgs.id');
|
||||
$list = $cloner->take(Base::getPaginate(50, 25, 'take'))->get();
|
||||
if ($list->isNotEmpty()) {
|
||||
$data = array_merge($data, $list->toArray());
|
||||
}
|
||||
}
|
||||
//
|
||||
$data = $builder->orderByDesc('read.msg_id')->paginate(Base::getPaginate(100, 50));
|
||||
if ($data->isEmpty()) {
|
||||
return Base::retError('empty');
|
||||
}
|
||||
return Base::retSuccess('success', $data);
|
||||
return Base::retSuccess('success', compact('data'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -618,9 +686,7 @@ class DialogController extends AbstractController
|
||||
->where('key', 'LIKE', "%{$key}%")
|
||||
->take(200)
|
||||
->pluck('id');
|
||||
return Base::retSuccess('success', [
|
||||
'data' => $data
|
||||
]);
|
||||
return Base::retSuccess('success', compact('data'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -660,7 +726,11 @@ class DialogController extends AbstractController
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__read
|
||||
*
|
||||
* @apiParam {Number} id 消息ID(组)
|
||||
* @apiParam {Object} id 消息ID(组)
|
||||
* - 1、多个ID用逗号分隔,如:1,2,3
|
||||
* - 2、另一种格式:{"id": "[会话ID]"},如:{"2": 0, "3": 10}
|
||||
* -- 会话ID:标记id之后的消息已读
|
||||
* -- 其他:标记已读
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@@ -671,17 +741,31 @@ class DialogController extends AbstractController
|
||||
$user = User::auth();
|
||||
//
|
||||
$id = Request::input('id');
|
||||
$ids = Base::explodeInt($id);
|
||||
$ids = $id && is_array($id) ? $id : array_fill_keys(Base::explodeInt($id), 'r');
|
||||
//
|
||||
$dialogIds = [];
|
||||
WebSocketDialogMsg::whereIn('id', $ids)->chunkById(20, function($list) use ($user, &$dialogIds) {
|
||||
$markIds = [];
|
||||
WebSocketDialogMsg::whereIn('id', array_keys($ids))->chunkById(100, function($list) use ($ids, $user, &$dialogIds, &$markIds) {
|
||||
/** @var WebSocketDialogMsg $item */
|
||||
foreach ($list as $item) {
|
||||
$item->readSuccess($user->userid);
|
||||
$dialogIds[$item->dialog_id] = $item->dialog_id;
|
||||
if ($ids[$item->id] == $item->dialog_id) {
|
||||
$markIds[$item->dialog_id] = min($item->id, $markIds[$item->dialog_id] ?? 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
//
|
||||
foreach ($markIds as $dialogId => $msgId) {
|
||||
WebSocketDialogMsgRead::whereDialogId($dialogId)
|
||||
->whereUserid($user->userid)
|
||||
->whereReadAt(null)
|
||||
->where('msg_id', '>=', $msgId)
|
||||
->chunkById(100, function ($list) {
|
||||
WebSocketDialogMsgRead::onlyMarkRead($list);
|
||||
});
|
||||
}
|
||||
//
|
||||
$data = [];
|
||||
$dialogUsers = WebSocketDialogUser::with(['webSocketDialog'])->whereUserid($user->userid)->whereIn('dialog_id', array_values($dialogIds))->get();
|
||||
foreach ($dialogUsers as $dialogUser) {
|
||||
@@ -695,7 +779,9 @@ class DialogController extends AbstractController
|
||||
$data[] = [
|
||||
'id' => $dialogUser->webSocketDialog->id,
|
||||
'unread' => $dialogUser->webSocketDialog->unread,
|
||||
'unread_one' => $dialogUser->webSocketDialog->unread_one,
|
||||
'mention' => $dialogUser->webSocketDialog->mention,
|
||||
'mention_ids' => $dialogUser->webSocketDialog->mention_ids,
|
||||
'user_at' => Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'),
|
||||
'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf()
|
||||
];
|
||||
@@ -738,7 +824,9 @@ class DialogController extends AbstractController
|
||||
return Base::retSuccess('success', [
|
||||
'id' => $dialogUser->webSocketDialog->id,
|
||||
'unread' => $dialogUser->webSocketDialog->unread,
|
||||
'unread_one' => $dialogUser->webSocketDialog->unread_one,
|
||||
'mention' => $dialogUser->webSocketDialog->mention,
|
||||
'mention_ids' => $dialogUser->webSocketDialog->mention_ids,
|
||||
'user_at' => Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'),
|
||||
'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf()
|
||||
]);
|
||||
@@ -812,18 +900,7 @@ class DialogController extends AbstractController
|
||||
public function msg__sendtext()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
if (!$user->bot) {
|
||||
$chatInformation = Base::settingFind('system', 'chat_information');
|
||||
if ($chatInformation == 'required') {
|
||||
if (empty($user->getRawOriginal('nickname'))) {
|
||||
return Base::retError('请设置昵称', [], -2);
|
||||
}
|
||||
if (empty($user->getRawOriginal('tel'))) {
|
||||
return Base::retError('请设置联系电话', [], -3);
|
||||
}
|
||||
}
|
||||
}
|
||||
$user->checkChatInformation();
|
||||
//
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$dialog_ids = trim(Request::input('dialog_ids'));
|
||||
@@ -837,7 +914,7 @@ class DialogController extends AbstractController
|
||||
//
|
||||
$result = [];
|
||||
$dialogIds = $dialog_ids ? explode(',', $dialog_ids) : [$dialog_id ?: 0];
|
||||
foreach($dialogIds as $dialog_id) {
|
||||
foreach ($dialogIds as $dialog_id) {
|
||||
//
|
||||
WebSocketDialog::checkDialog($dialog_id);
|
||||
//
|
||||
@@ -884,13 +961,13 @@ class DialogController extends AbstractController
|
||||
'ext' => $ext,
|
||||
];
|
||||
$result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'file', $fileData, $user->userid, false, false, $silence);
|
||||
} else {
|
||||
$msgData = ['text' => $text];
|
||||
if ($markdown) {
|
||||
$msgData['type'] = 'md';
|
||||
}
|
||||
$result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'text', $msgData, $user->userid, false, false, $silence);
|
||||
}
|
||||
//
|
||||
$msgData = ['text' => $text];
|
||||
if ($markdown) {
|
||||
$msgData['type'] = 'md';
|
||||
}
|
||||
$result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'text', $msgData, $user->userid, false, false, $silence);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
@@ -915,6 +992,7 @@ class DialogController extends AbstractController
|
||||
public function msg__sendrecord()
|
||||
{
|
||||
$user = User::auth();
|
||||
$user->checkChatInformation();
|
||||
//
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$reply_id = intval(Request::input('reply_id'));
|
||||
@@ -964,6 +1042,7 @@ class DialogController extends AbstractController
|
||||
public function msg__sendfile()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$dialogIds = [intval(Request::input('dialog_id'))];
|
||||
$replyId = intval(Request::input('reply_id'));
|
||||
$imageAttachment = intval(Request::input('image_attachment'));
|
||||
@@ -996,6 +1075,7 @@ class DialogController extends AbstractController
|
||||
public function msg__sendfiles()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$files = Request::file('files');
|
||||
$image64 = Request::input('image64');
|
||||
$fileName = Request::input('filename');
|
||||
@@ -1327,6 +1407,7 @@ class DialogController extends AbstractController
|
||||
}
|
||||
switch ($type) {
|
||||
case 'read':
|
||||
// 标记已读
|
||||
$builder = WebSocketDialogMsgRead::whereDialogId($dialog_id)->whereUserid($user->userid)->whereReadAt(null);
|
||||
if ($after_msg_id > 0) {
|
||||
$builder->where('msg_id', '>=', $after_msg_id);
|
||||
@@ -1334,32 +1415,28 @@ class DialogController extends AbstractController
|
||||
$builder->chunkById(100, function ($list) {
|
||||
WebSocketDialogMsgRead::onlyMarkRead($list);
|
||||
});
|
||||
//
|
||||
$dialogUser->webSocketDialog->generateUnread($user->userid);
|
||||
$data = [
|
||||
'id' => $dialogUser->webSocketDialog->id,
|
||||
'unread' => $dialogUser->webSocketDialog->unread,
|
||||
'mention' => $dialogUser->webSocketDialog->mention,
|
||||
'mark_unread' => 0,
|
||||
];
|
||||
break;
|
||||
|
||||
case 'unread':
|
||||
$data = [
|
||||
'id' => $dialogUser->webSocketDialog->id,
|
||||
'mark_unread' => 1,
|
||||
];
|
||||
// 标记未读
|
||||
break;
|
||||
|
||||
default:
|
||||
return Base::retError("参数错误");
|
||||
}
|
||||
$dialogUser->mark_unread = $data['mark_unread'];
|
||||
$dialogUser->mark_unread = $type == 'unread' ? 1 : 0;
|
||||
$dialogUser->save();
|
||||
return Base::retSuccess("success", array_merge($data, [
|
||||
$dialogUser->webSocketDialog->generateUnread($user->userid);
|
||||
return Base::retSuccess("success", [
|
||||
'id' => $dialogUser->webSocketDialog->id,
|
||||
'unread' => $dialogUser->webSocketDialog->unread,
|
||||
'unread_one' => $dialogUser->webSocketDialog->unread_one,
|
||||
'mention' => $dialogUser->webSocketDialog->mention,
|
||||
'mention_ids' => $dialogUser->webSocketDialog->mention_ids,
|
||||
'user_at' => Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'),
|
||||
'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf(),
|
||||
]));
|
||||
'mark_unread' => $dialogUser->mark_unread,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1642,6 +1719,12 @@ class DialogController extends AbstractController
|
||||
if (Base::isSuccess($res)) {
|
||||
$add = $res['data'];
|
||||
}
|
||||
//
|
||||
$msg->webSocketDialog?->pushMsg('update', [
|
||||
'id' => $msg->id,
|
||||
'todo' => $msg->todo,
|
||||
'dialog_id' => $msg->dialog_id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -2100,43 +2183,66 @@ class DialogController extends AbstractController
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$uuid = trim(Request::input('uuid'));
|
||||
$text = trim(Request::input('text'));
|
||||
$list = Request::input('list');
|
||||
$list = Request::input('list') ?? [];
|
||||
//
|
||||
WebSocketDialog::checkDialog($dialog_id);
|
||||
$strlen = mb_strlen($text);
|
||||
$noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
|
||||
if ($strlen < 1) {
|
||||
if ($strlen < 1 || empty($list)) {
|
||||
return Base::retError('内容不能为空');
|
||||
}
|
||||
if ($noimglen > 200000) {
|
||||
return Base::retError('内容最大不能超过200000字');
|
||||
}
|
||||
//
|
||||
$userid = $user->userid;
|
||||
if ($uuid) {
|
||||
$dialogMsg = WebSocketDialogMsg::whereDialogId($dialog_id)
|
||||
->whereType('word-chain')
|
||||
->orderByDesc('created_at')
|
||||
->where('msg', 'like', "%$uuid%")
|
||||
->value('msg');
|
||||
$list = array_reverse(array_merge($dialogMsg['list'] ?? [], $list));
|
||||
$list = array_reduce($list, function ($result, $item) {
|
||||
$fieldValue = $item['id']; // 指定字段名
|
||||
if (!isset($result[$fieldValue])) {
|
||||
$result[$fieldValue] = $item;
|
||||
return AbstractModel::transaction(function () use ($user, $uuid, $dialog_id, $list, $text) {
|
||||
if ($uuid) {
|
||||
$dialogMsg = WebSocketDialogMsg::whereDialogId($dialog_id)
|
||||
->lockForUpdate()
|
||||
->whereType('word-chain')
|
||||
->orderByDesc('created_at')
|
||||
->where('msg', 'like', "%$uuid%")
|
||||
->value('msg');
|
||||
//
|
||||
$createId = $dialogMsg['createid'] ?? $user->userid;
|
||||
// 新增
|
||||
$msgList = $dialogMsg['list'] ?? [];
|
||||
$addList = array_udiff($list, $msgList, function($a, $b) {
|
||||
return ($a['id'] ?? 0) - $b['id'];
|
||||
});
|
||||
foreach ($addList as $key => $item) {
|
||||
$item['id'] = intval(round(microtime(true) * 1000)) + $key;
|
||||
$msgList[] = $item;
|
||||
}
|
||||
return $result;
|
||||
}, []);
|
||||
$list = array_reverse(array_values($list));
|
||||
}
|
||||
//
|
||||
$msgData = [
|
||||
'text' => $text,
|
||||
'list' => $list,
|
||||
'userid' => $userid,
|
||||
'uuid' => $uuid ?: Base::generatePassword(36),
|
||||
];
|
||||
return WebSocketDialogMsg::sendMsg(null, $dialog_id, 'word-chain', $msgData, $user->userid);
|
||||
// 编辑更新
|
||||
$lists = array_column($list,null,'id');
|
||||
foreach ($msgList as $key => $item) {
|
||||
if (isset($lists[$item['id']]) && $item['userid'] == $user->userid) {
|
||||
$msgList[$key] = $lists[$item['id']];
|
||||
}
|
||||
}
|
||||
$list = $msgList;
|
||||
} else {
|
||||
$createId = $user->userid;
|
||||
$uuid = Base::generatePassword(36);
|
||||
foreach ($list as $key => $item) {
|
||||
$list[$key]['id'] = intval(round(microtime(true) * 1000)) + $key;
|
||||
}
|
||||
}
|
||||
//
|
||||
usort($list, function ($a, $b) {
|
||||
return $a['id'] - $b['id'];
|
||||
});
|
||||
//
|
||||
$msgData = [
|
||||
'text' => $text,
|
||||
'list' => $list,
|
||||
'userid' => $user->userid,
|
||||
'createid' => $createId,
|
||||
'uuid' => $uuid,
|
||||
];
|
||||
return WebSocketDialogMsg::sendMsg(null, $dialog_id, 'word-chain', $msgData, $user->userid);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2177,8 +2283,6 @@ class DialogController extends AbstractController
|
||||
WebSocketDialog::checkDialog($dialog_id);
|
||||
//
|
||||
$action = null;
|
||||
$userid = $user->userid;
|
||||
$result = [];
|
||||
if ($type != 'create') {
|
||||
if ($type == 'vote' && empty($votes)) {
|
||||
return Base::retError('参数错误');
|
||||
@@ -2186,42 +2290,50 @@ class DialogController extends AbstractController
|
||||
if (empty($uuid)) {
|
||||
return Base::retError('参数错误');
|
||||
}
|
||||
$dialogMsgs = WebSocketDialogMsg::whereDialogId($dialog_id)
|
||||
->whereType('vote')
|
||||
->orderByDesc('created_at')
|
||||
->where('msg', 'like', "%$uuid%")
|
||||
->get();
|
||||
//
|
||||
if ($type == 'again') {
|
||||
$res = WebSocketDialogMsg::sendMsg(null, $dialog_id, 'vote', $dialogMsgs[0]->msg, $user->userid);
|
||||
if (Base::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
$result[] = $res['data'];
|
||||
} else {
|
||||
foreach ($dialogMsgs as $dialogMsg) {
|
||||
$action = "change-{$dialogMsg->id}";
|
||||
$msgData = $dialogMsg->msg;
|
||||
if ($type == 'finish') {
|
||||
$msgData['state'] = 0;
|
||||
} else {
|
||||
$msgDataVotes = $msgData['votes'] ?? [];
|
||||
if (in_array($userid, array_column($msgDataVotes, 'userid'))) {
|
||||
return Base::retError('不能重复投票');
|
||||
}
|
||||
$msgDataVotes[] = [
|
||||
'userid' => $userid,
|
||||
'votes' => $votes,
|
||||
];
|
||||
$msgData['votes'] = $msgDataVotes;
|
||||
}
|
||||
$res = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'vote', $msgData, $user->userid);
|
||||
return AbstractModel::transaction(function () use ($user, $uuid, $dialog_id, $type, $votes) {
|
||||
//
|
||||
$dialogMsgs = WebSocketDialogMsg::whereDialogId($dialog_id)
|
||||
->lockForUpdate()
|
||||
->whereType('vote')
|
||||
->orderByDesc('created_at')
|
||||
->where('msg', 'like', "%$uuid%")
|
||||
->get();
|
||||
//
|
||||
$result = [];
|
||||
if ($type == 'again') {
|
||||
$res = WebSocketDialogMsg::sendMsg(null, $dialog_id, 'vote', $dialogMsgs[0]->msg, $user->userid);
|
||||
if (Base::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
$result[] = $res['data'];
|
||||
} else {
|
||||
foreach ($dialogMsgs as $dialogMsg) {
|
||||
$action = "change-{$dialogMsg->id}";
|
||||
$msgData = $dialogMsg->msg;
|
||||
if ($type == 'finish') {
|
||||
$msgData['state'] = 0;
|
||||
} else {
|
||||
$msgDataVotes = $msgData['votes'] ?? [];
|
||||
if (in_array($user->userid, array_column($msgDataVotes, 'userid'))) {
|
||||
return Base::retError('不能重复投票');
|
||||
}
|
||||
$msgDataVotes[] = [
|
||||
'userid' => $user->userid,
|
||||
'votes' => $votes,
|
||||
];
|
||||
$msgData['votes'] = $msgDataVotes;
|
||||
}
|
||||
//
|
||||
$res = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'vote', $msgData, $user->userid);
|
||||
if (Base::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
$result[] = $res['data'];
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('发送成功', $result);
|
||||
});
|
||||
} else {
|
||||
$strlen = mb_strlen($text);
|
||||
$noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
|
||||
@@ -2234,7 +2346,7 @@ class DialogController extends AbstractController
|
||||
$msgData = [
|
||||
'text' => $text,
|
||||
'list' => $list,
|
||||
'userid' => $userid,
|
||||
'userid' => $user->userid,
|
||||
'uuid' => $uuid ?: Base::generatePassword(36),
|
||||
'multiple' => $multiple,
|
||||
'anonymous' => $anonymous,
|
||||
@@ -2245,9 +2357,8 @@ class DialogController extends AbstractController
|
||||
if (Base::isError($res)) {
|
||||
return $res;
|
||||
}
|
||||
$result[] = $res['data'];
|
||||
return Base::retSuccess('发送成功', [$res['data']]);
|
||||
}
|
||||
return Base::retSuccess('发送成功', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2283,13 +2394,14 @@ class DialogController extends AbstractController
|
||||
$dialog->save();
|
||||
//
|
||||
$data = [
|
||||
'add' => null,
|
||||
'update' => [
|
||||
'dialog_id' => $dialog->id,
|
||||
'top_msg_id' => $dialog->top_msg_id,
|
||||
'top_userid' => $dialog->top_userid,
|
||||
]
|
||||
];
|
||||
$res = $msg->sendMsg(null, $dialog->id, 'top', [
|
||||
$res = WebSocketDialogMsg::sendMsg(null, $dialog->id, 'top', [
|
||||
'action' => $dialog->top_msg_id ? 'add' : 'remove',
|
||||
'data' => [
|
||||
'id' => $msg->id,
|
||||
|
||||
@@ -699,6 +699,9 @@ class FileController extends AbstractController
|
||||
* @apiName content__upload
|
||||
*
|
||||
* @apiParam {Number} [pid] 父级ID
|
||||
* @apiParam {Number} [cover] 覆盖已存在的文件
|
||||
* - 0:不覆盖,保留两者(默认)
|
||||
* - 1:覆盖
|
||||
* @apiParam {String} [files] 文件名
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
@@ -709,8 +712,9 @@ class FileController extends AbstractController
|
||||
{
|
||||
$user = User::auth();
|
||||
$pid = intval(Request::input('pid'));
|
||||
$overwrite = intval(Request::input('cover'));
|
||||
$webkitRelativePath = Request::input('webkitRelativePath');
|
||||
$data = (new File)->contentUpload($user, $pid, $webkitRelativePath);
|
||||
$data = (new File)->contentUpload($user, $pid, $webkitRelativePath, $overwrite);
|
||||
return Base::retSuccess($data['data']['name'] . ' 上传成功', $data['addItem']);
|
||||
}
|
||||
|
||||
@@ -1028,6 +1032,12 @@ class FileController extends AbstractController
|
||||
return Base::retError('一次最多可以下载100个文件或文件夹');
|
||||
}
|
||||
|
||||
$botUser = User::botGetOrCreate('system-msg');
|
||||
if (empty($botUser)) {
|
||||
return Base::retError('系统机器人不存在');
|
||||
}
|
||||
$dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid);
|
||||
|
||||
$files = [];
|
||||
$totalSize = 0;
|
||||
|
||||
@@ -1053,7 +1063,7 @@ class FileController extends AbstractController
|
||||
return Base::retError('创建压缩文件失败');
|
||||
}
|
||||
|
||||
go(function () use ($zipPath, $fileUrl, $user, $zip, $files, $fileName, $zipFile) {
|
||||
go(function () use ($zipPath, $fileUrl, $zip, $files, $fileName, $botUser, $dialog) {
|
||||
Coroutine::sleep(0.1);
|
||||
// 压缩进度
|
||||
$progress = 0;
|
||||
@@ -1079,20 +1089,14 @@ class FileController extends AbstractController
|
||||
]);
|
||||
}
|
||||
//
|
||||
$botUser = User::botGetOrCreate('system-msg');
|
||||
if (empty($botUser)) {
|
||||
return;
|
||||
}
|
||||
if ($dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid)) {
|
||||
$text = "<b>文件下载打包已完成。</b>";
|
||||
$text .= "\n\n";
|
||||
$text .= "文件名:{$fileName}";
|
||||
$text .= "\n";
|
||||
$text .= "文件大小:".Base::twoFloat(filesize($zipPath) / 1024, true)."KB";
|
||||
$text .= "\n";
|
||||
$text .= '<a href="' . $fileUrl . '" target="_blank"><button type="button" class="ivu-btn ivu-btn-warning" style="margin-top: 10px;"><span>立即下载</span></button></a>';
|
||||
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||
}
|
||||
$text = "<b>文件下载打包已完成。</b>";
|
||||
$text .= "\n\n";
|
||||
$text .= "文件名:{$fileName}";
|
||||
$text .= "\n";
|
||||
$text .= "文件大小:".Base::twoFloat(filesize($zipPath) / 1024, true)."KB";
|
||||
$text .= "\n";
|
||||
$text .= '<a href="' . $fileUrl . '" target="_blank"><button type="button" class="ivu-btn ivu-btn-warning" style="margin-top: 10px;"><span>立即下载</span></button></a>';
|
||||
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||
});
|
||||
return Base::retSuccess('success', [
|
||||
'name' => $fileName,
|
||||
|
||||
@@ -1200,7 +1200,13 @@ class ProjectController extends AbstractController
|
||||
if (Carbon::parse($time[1])->timestamp - Carbon::parse($time[0])->timestamp > 90 * 86400) {
|
||||
return Base::retError('时间范围限制最大90天');
|
||||
}
|
||||
go(function () use ($user, $userid, $time, $type) {
|
||||
$botUser = User::botGetOrCreate('system-msg');
|
||||
if (empty($botUser)) {
|
||||
return Base::retError('系统机器人不存在');
|
||||
}
|
||||
$dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid);
|
||||
//
|
||||
go(function () use ($user, $userid, $time, $type, $botUser, $dialog) {
|
||||
Coroutine::sleep(0.1);
|
||||
$headings = [];
|
||||
$headings[] = '任务ID';
|
||||
@@ -1221,6 +1227,9 @@ class ProjectController extends AbstractController
|
||||
$headings[] = '状态';
|
||||
$datas = [];
|
||||
//
|
||||
$text = '<b>导出任务统计已完成。</b>';
|
||||
$text .= "\n\n";
|
||||
//
|
||||
$builder = ProjectTask::select(['project_tasks.*', 'project_task_users.userid as ownerid'])
|
||||
->join('project_task_users', 'project_tasks.id', '=', 'project_task_users.task_id')
|
||||
->where('project_task_users.owner', 1)
|
||||
@@ -1318,7 +1327,9 @@ class ProjectController extends AbstractController
|
||||
}
|
||||
});
|
||||
if (empty($datas)) {
|
||||
return Base::retError('没有任何数据');
|
||||
$text .= '没有任何数据';
|
||||
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||
return;
|
||||
}
|
||||
//
|
||||
$sheets = [];
|
||||
@@ -1334,15 +1345,18 @@ class ProjectController extends AbstractController
|
||||
//
|
||||
$fileName = User::userid2nickname($userid[0]) ?: $userid[0];
|
||||
if (count($userid) > 1) {
|
||||
$fileName .= "等" . count($userid) . "位成员";
|
||||
$fileName .= '等' . count($userid) . '位成员任务统计';
|
||||
}
|
||||
$fileName .= '任务统计_' . Base::time() . '.xls';
|
||||
$fileName .= '_' . Base::time() . '.xls';
|
||||
$filePath = "temp/task/export/" . date("Ym", Base::time());
|
||||
$export = new BillMultipleExport($sheets);
|
||||
$res = $export->store($filePath . "/" . $fileName);
|
||||
if ($res != 1) {
|
||||
return Base::retError('导出失败,' . $fileName . '!');
|
||||
$text .= "导出失败,{$fileName}!";
|
||||
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||
return;
|
||||
}
|
||||
//
|
||||
$xlsPath = storage_path("app/" . $filePath . "/" . $fileName);
|
||||
$zipFile = "app/" . $filePath . "/" . Base::rightDelete($fileName, '.xls') . ".zip";
|
||||
$zipPath = storage_path($zipFile);
|
||||
@@ -1360,21 +1374,15 @@ class ProjectController extends AbstractController
|
||||
]));
|
||||
$fileUrl = Base::fillUrl('api/project/task/down?key=' . urlencode($base64));
|
||||
Session::put('task::export:userid', $user->userid);
|
||||
$botUser = User::botGetOrCreate('system-msg');
|
||||
if (empty($botUser)) {
|
||||
return;
|
||||
}
|
||||
if ($dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid)) {
|
||||
$text = "<b>导出任务统计已完成。</b>";
|
||||
$text .= "\n\n";
|
||||
$text .= "文件名:{$fileName}";
|
||||
$text .= "\n";
|
||||
$text .= "文件大小:" . Base::twoFloat(filesize($zipPath) / 1024, true) . "KB";
|
||||
$text .= "\n";
|
||||
$text .= '<a href="' . $fileUrl . '" target="_blank"><button type="button" class="ivu-btn ivu-btn-warning" style="margin-top: 10px;"><span>立即下载</span></button></a>';
|
||||
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||
}
|
||||
$text .= "文件名:{$fileName}";
|
||||
$text .= "\n";
|
||||
$text .= "文件大小:" . Base::twoFloat(filesize($zipPath) / 1024, true) . "KB";
|
||||
$text .= "\n";
|
||||
$text .= '<a href="' . $fileUrl . '" target="_blank"><button type="button" class="ivu-btn ivu-btn-warning" style="margin-top: 10px;"><span>立即下载</span></button></a>';
|
||||
} else {
|
||||
$text .= '打包失败,请稍后再试...';
|
||||
}
|
||||
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||
});
|
||||
return Base::retSuccess('success', ['msg' => '正在打包,请留意系统消息。']);
|
||||
}
|
||||
@@ -2293,7 +2301,7 @@ class ProjectController extends AbstractController
|
||||
$project = Project::userProject($task->project_id);
|
||||
ProjectPermission::userTaskPermission($project, ProjectPermission::TASK_MOVE, $task);
|
||||
//
|
||||
if( $task->project_id == $project_id && $task->column_id == $column_id){
|
||||
if ($task->project_id == $project_id && $task->column_id == $column_id) {
|
||||
return Base::retSuccess('移动成功', ['id' => $task_id]);
|
||||
}
|
||||
//
|
||||
@@ -2302,7 +2310,7 @@ class ProjectController extends AbstractController
|
||||
if (empty($column)) {
|
||||
return Base::retError('列表不存在');
|
||||
}
|
||||
if($flow_item_id){
|
||||
if ($flow_item_id) {
|
||||
$flowItem = projectFlowItem::whereProjectId($project->id)->whereId($flow_item_id)->first();
|
||||
if (empty($flowItem)) {
|
||||
return Base::retError('任务状态不存在');
|
||||
@@ -2455,6 +2463,21 @@ class ProjectController extends AbstractController
|
||||
'week' => Doo::translate("周" . Base::getTimeWeek($timestamp)),
|
||||
'segment' => Doo::translate(Base::getTimeDayeSegment($timestamp)),
|
||||
];
|
||||
$record = Base::json2array($log->record);
|
||||
if (is_array($record['change'])) {
|
||||
foreach ($record['change'] as &$item) {
|
||||
$item = preg_replace_callback('/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/', function ($matches) {
|
||||
$time = strtotime($matches[0]);
|
||||
$second = date("s", $time);
|
||||
$second = $second === "00" ? "" : ":$second";
|
||||
if (date("Y") === date("Y", $time)) {
|
||||
return date("m-d H:i", $time) . $second;
|
||||
}
|
||||
return date("Y-m-d H:i", $time) . $second;
|
||||
}, $item);
|
||||
}
|
||||
$log->record = $record;
|
||||
}
|
||||
return $log;
|
||||
});
|
||||
//
|
||||
|
||||
@@ -2,15 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\UserBot;
|
||||
use App\Models\UserCheckinMac;
|
||||
use App\Models\UserCheckinRecord;
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use App\Module\Base;
|
||||
use Cache;
|
||||
use Carbon\Carbon;
|
||||
use Request;
|
||||
|
||||
/**
|
||||
|
||||
@@ -316,13 +316,16 @@ class ReportController extends AbstractController
|
||||
// 未完成的任务
|
||||
$unfinishedContent = "";
|
||||
$unfinished_task = ProjectTask::query()
|
||||
->whereNull("complete_at")
|
||||
->whereNotNull("start_at")
|
||||
->where("end_at", "<", $end_time->toDateTimeString())
|
||||
->join("projects", "projects.id", "=", "project_tasks.project_id")
|
||||
->whereNull("projects.archived_at")
|
||||
->whereNull("project_tasks.complete_at")
|
||||
->whereNotNull("project_tasks.start_at")
|
||||
->where("project_tasks.end_at", "<", $end_time->toDateTimeString())
|
||||
->whereHas("taskUser", function ($query) use ($user) {
|
||||
$query->where("userid", $user->userid);
|
||||
})
|
||||
->orderByDesc("id")
|
||||
->select("project_tasks.*")
|
||||
->orderByDesc("project_tasks.id")
|
||||
->get();
|
||||
if ($unfinished_task->isNotEmpty()) {
|
||||
foreach ($unfinished_task as $task) {
|
||||
|
||||
@@ -40,7 +40,7 @@ class SystemController extends AbstractController
|
||||
* @apiParam {String} type
|
||||
* - get: 获取(默认)
|
||||
* - all: 获取所有(需要管理员权限)
|
||||
* - save: 保存设置(参数:['reg', 'reg_identity', 'reg_invite', 'login_code', 'password_policy', 'project_invite', 'chat_information', 'anon_message', 'auto_archived', 'archived_day', 'task_visible', 'task_default_time', 'all_group_mute', 'all_group_autoin', 'image_compress', 'image_save_local', 'start_home'])
|
||||
* - save: 保存设置(参数:['reg', 'reg_identity', 'reg_invite', 'temp_account_alias', 'login_code', 'password_policy', 'project_invite', 'chat_information', 'anon_message', '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', 'image_compress', 'image_save_local', 'start_home'])
|
||||
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@@ -60,17 +60,21 @@ class SystemController extends AbstractController
|
||||
'reg',
|
||||
'reg_identity',
|
||||
'reg_invite',
|
||||
'temp_account_alias',
|
||||
'login_code',
|
||||
'password_policy',
|
||||
'project_invite',
|
||||
'chat_information',
|
||||
'anon_message',
|
||||
'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',
|
||||
'image_compress',
|
||||
'image_save_local',
|
||||
'start_home',
|
||||
@@ -96,30 +100,35 @@ class SystemController extends AbstractController
|
||||
//
|
||||
if ($type == 'all' || $type == 'save') {
|
||||
User::auth('admin');
|
||||
$setting['reg_invite'] = $setting['reg_invite'] ?: Base::generatePassword(8);
|
||||
$setting['reg_invite'] = $setting['reg_invite'] ?: Base::generatePassword();
|
||||
} else {
|
||||
if (isset($setting['reg_invite'])) unset($setting['reg_invite']);
|
||||
}
|
||||
//
|
||||
$setting['reg'] = $setting['reg'] ?: 'open';
|
||||
$setting['reg_identity'] = $setting['reg_identity'] ?: 'normal';
|
||||
$setting['temp_account_alias'] = $setting['temp_account_alias'] ?: '';
|
||||
$setting['login_code'] = $setting['login_code'] ?: 'auto';
|
||||
$setting['password_policy'] = $setting['password_policy'] ?: 'simple';
|
||||
$setting['project_invite'] = $setting['project_invite'] ?: 'open';
|
||||
$setting['chat_information'] = $setting['chat_information'] ?: 'optional';
|
||||
$setting['anon_message'] = $setting['anon_message'] ?: 'open';
|
||||
$setting['e2e_message'] = $setting['e2e_message'] ?: 'close';
|
||||
$setting['auto_archived'] = $setting['auto_archived'] ?: 'close';
|
||||
$setting['archived_day'] = floatval($setting['archived_day']) ?: 7;
|
||||
$setting['task_visible'] = $setting['task_visible'] ?: 'close';
|
||||
$setting['task_default_time'] = $setting['task_default_time'] ? Base::json2array($setting['task_default_time']) : ['09:00', '18:00'];
|
||||
$setting['all_group_mute'] = $setting['all_group_mute'] ?: 'open';
|
||||
$setting['all_group_autoin'] = $setting['all_group_autoin'] ?: 'yes';
|
||||
$setting['user_private_chat_mute'] = $setting['user_private_chat_mute'] ?: 'open';
|
||||
$setting['user_group_chat_mute'] = $setting['user_group_chat_mute'] ?: 'open';
|
||||
$setting['image_compress'] = $setting['image_compress'] ?: 'open';
|
||||
$setting['image_save_local'] = $setting['image_save_local'] ?: 'open';
|
||||
$setting['start_home'] = $setting['start_home'] ?: 'close';
|
||||
$setting['file_upload_limit'] = $setting['file_upload_limit'] ?: '';
|
||||
$setting['unclaimed_task_reminder'] = $setting['unclaimed_task_reminder'] ?: 'close';
|
||||
$setting['unclaimed_task_reminder_time'] = $setting['unclaimed_task_reminder_time'] ?: '';
|
||||
$setting['server_version'] = Base::getVersion();
|
||||
//
|
||||
return Base::retSuccess('success', $setting ?: json_decode('{}'));
|
||||
}
|
||||
@@ -195,7 +204,7 @@ class SystemController extends AbstractController
|
||||
*
|
||||
* @apiParam {String} type
|
||||
* - get: 获取(默认)
|
||||
* - save: 保存设置(参数:['open', 'appid', 'app_certificate'])
|
||||
* - save: 保存设置(参数:['open', 'appid', 'app_certificate', 'api_key', 'api_secret'])
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
@@ -215,12 +224,14 @@ class SystemController extends AbstractController
|
||||
'open',
|
||||
'appid',
|
||||
'app_certificate',
|
||||
'api_key',
|
||||
'api_secret',
|
||||
])) {
|
||||
unset($all[$key]);
|
||||
}
|
||||
}
|
||||
if ($all['open'] === 'open' && (!$all['appid'] || !$all['app_certificate'])) {
|
||||
return Base::retError('请填写完整的参数');
|
||||
return Base::retError('请填写基本配置');
|
||||
}
|
||||
$setting = Base::setting('meetingSetting', Base::newTrim($all));
|
||||
} else {
|
||||
@@ -231,6 +242,8 @@ class SystemController extends AbstractController
|
||||
if (env("SYSTEM_SETTING") == 'disabled') {
|
||||
$setting['appid'] = substr($setting['appid'], 0, 4) . str_repeat('*', strlen($setting['appid']) - 8) . substr($setting['appid'], -4);
|
||||
$setting['app_certificate'] = substr($setting['app_certificate'], 0, 4) . str_repeat('*', strlen($setting['app_certificate']) - 8) . substr($setting['app_certificate'], -4);
|
||||
$setting['api_key'] = substr($setting['api_key'], 0, 4) . str_repeat('*', strlen($setting['api_key']) - 8) . substr($setting['api_key'], -4);
|
||||
$setting['api_secret'] = substr($setting['api_secret'], 0, 4) . str_repeat('*', strlen($setting['api_secret']) - 8) . substr($setting['api_secret'], -4);
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('success', $setting ?: json_decode('{}'));
|
||||
@@ -267,7 +280,10 @@ class SystemController extends AbstractController
|
||||
'wenxin_secret',
|
||||
'wenxin_model',
|
||||
'qianwen_key',
|
||||
'qianwen_model'
|
||||
'qianwen_model',
|
||||
'gemini_key',
|
||||
'gemini_model',
|
||||
'gemini_agency',
|
||||
];
|
||||
|
||||
if ($type == 'save') {
|
||||
@@ -307,11 +323,18 @@ class SystemController extends AbstractController
|
||||
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => "设置成功"], $botUser->userid, true, false, true);
|
||||
}
|
||||
}
|
||||
if ($backup['gemini_key'] != $setting['gemini_key']) {
|
||||
$botUser = User::botGetOrCreate('ai-gemini');
|
||||
if ($botUser && $dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid)) {
|
||||
WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => "设置成功"], $botUser->userid, true, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
$setting['openai_model'] = $setting['openai_model'] ?: 'gpt-3.5-turbo';
|
||||
$setting['wenxin_model'] = $setting['wenxin_model'] ?: 'eb-instant';
|
||||
$setting['qianwen_model'] = $setting['qianwen_model'] ?: 'qwen-v1';
|
||||
$setting['gemini_model'] = $setting['gemini_model'] ?: 'gemini-1.0-pro';
|
||||
if (env("SYSTEM_SETTING") == 'disabled') {
|
||||
foreach ($keys as $item) {
|
||||
if (strlen($setting[$item]) > 12) {
|
||||
@@ -385,6 +408,9 @@ class SystemController extends AbstractController
|
||||
$setting['edit'] = $setting['edit'] ?: 'close';
|
||||
$setting['modes'] = is_array($setting['modes']) ? $setting['modes'] : [];
|
||||
$setting['cmd'] = "curl -sSL '" . Base::fillUrl("api/public/checkin/install?key={$setting['key']}") . "' | sh";
|
||||
if (Base::judgeClientVersion('0.34.67')) {
|
||||
$setting['cmd'] = base64_encode($setting['cmd']);
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('success', $setting ?: json_decode('{}'));
|
||||
}
|
||||
@@ -1191,7 +1217,7 @@ class SystemController extends AbstractController
|
||||
if (count($users) > 1) {
|
||||
$fileName .= "等" . count($userid) . "位成员";
|
||||
}
|
||||
$fileName .= '签到记录_' . Base::time() . '.xls';
|
||||
$fileName .= '签到记录_' . Base::time() . '.xlsx';
|
||||
$filePath = "temp/checkin/export/" . date("Ym", Base::time());
|
||||
$export = new BillMultipleExport($sheets);
|
||||
$res = $export->store($filePath . "/" . $fileName);
|
||||
@@ -1199,7 +1225,7 @@ class SystemController extends AbstractController
|
||||
return Base::retError('导出失败,' . $fileName . '!');
|
||||
}
|
||||
$xlsPath = storage_path("app/" . $filePath . "/" . $fileName);
|
||||
$zipFile = "app/" . $filePath . "/" . Base::rightDelete($fileName, '.xls') . ".zip";
|
||||
$zipFile = "app/" . $filePath . "/" . Base::rightDelete($fileName, '.xlsx') . ".zip";
|
||||
$zipPath = storage_path($zipFile);
|
||||
if (file_exists($zipPath)) {
|
||||
Base::deleteDirAndFile($zipPath, true);
|
||||
@@ -1256,8 +1282,14 @@ class SystemController extends AbstractController
|
||||
* @apiGroup system
|
||||
* @apiName version
|
||||
*
|
||||
* @apiSuccess {String} version
|
||||
* @apiSuccess {String} publish
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
{
|
||||
"version": "0.0.1",
|
||||
"publish": {
|
||||
"provider": "generic",
|
||||
"url": ""
|
||||
}
|
||||
}
|
||||
*/
|
||||
public function version()
|
||||
{
|
||||
@@ -1279,4 +1311,52 @@ class SystemController extends AbstractController
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/prefetch 25. 预加载的资源
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName prefetch
|
||||
*
|
||||
* @apiSuccessExample {array} Success-Response:
|
||||
[
|
||||
"https://......",
|
||||
"https://......",
|
||||
"......",
|
||||
]
|
||||
*/
|
||||
public function prefetch()
|
||||
{
|
||||
$userAgent = strtolower(Request::server('HTTP_USER_AGENT'));
|
||||
$isMain = str_contains($userAgent, 'maintaskwindow');
|
||||
$isApp = str_contains($userAgent, 'kuaifan_eeui');
|
||||
$version = Base::getVersion();
|
||||
$array = [];
|
||||
|
||||
if ($isMain || $isApp) {
|
||||
$path = 'js/build/';
|
||||
$list = Base::readDir(public_path($path), false);
|
||||
foreach ($list as $item) {
|
||||
if (is_file($item) && filesize($item) > 50 * 1024) {
|
||||
$array[] = $path . basename($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($isMain) {
|
||||
$file = base_path('.prefetch');
|
||||
if (file_exists($file)) {
|
||||
$content = file_get_contents($file);
|
||||
$items = explode("\n", $content);
|
||||
$array = array_merge($array, $items);
|
||||
}
|
||||
}
|
||||
|
||||
return array_map(function($item) use ($version) {
|
||||
$url = trim($item);
|
||||
$url = str_replace('{version}', $version, $url);
|
||||
return url($url);
|
||||
}, array_values(array_filter($array)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ use App\Models\UserDepartment;
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Models\UserCheckinRecord;
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Models\UserEmailVerification;
|
||||
use App\Module\AgoraIO\AgoraTokenGenerator;
|
||||
|
||||
@@ -570,9 +571,9 @@ class UsersController extends AbstractController
|
||||
$list->transform(function (User $userInfo) use ($user, $state) {
|
||||
$tags = [];
|
||||
$dep = $userInfo->getDepartmentName();
|
||||
$dep = array_filter(explode(",", $dep), function($item) {
|
||||
$dep = array_values(array_filter(explode(",", $dep), function($item) {
|
||||
return preg_match("/\(M\)$/", $item);
|
||||
});
|
||||
}));
|
||||
if ($dep) {
|
||||
$tags[] = preg_replace("/\(M\)$/", "", trim($dep[0])) . Doo::translate("负责人");
|
||||
}
|
||||
@@ -581,7 +582,7 @@ class UsersController extends AbstractController
|
||||
$tags[] = Doo::translate("系统管理员");
|
||||
}
|
||||
if ($userInfo->isTemp()) {
|
||||
$tags[] = Doo::translate("临时帐号");
|
||||
$tags[] = User::tempAccountAlias(); // 临时帐号
|
||||
}
|
||||
if ($userInfo->userid > 3 && Carbon::parse($userInfo->created_at)->isAfter(Carbon::now()->subDays(30))) {
|
||||
$tags[] = Doo::translate("新帐号");
|
||||
@@ -614,7 +615,7 @@ class UsersController extends AbstractController
|
||||
public function basic()
|
||||
{
|
||||
$sharekey = Request::header('sharekey');
|
||||
if(empty($sharekey) || !Meeting::getShareInfo($sharekey)){
|
||||
if (empty($sharekey) || !Meeting::getShareInfo($sharekey)) {
|
||||
User::auth();
|
||||
}
|
||||
//
|
||||
@@ -767,7 +768,7 @@ class UsersController extends AbstractController
|
||||
//
|
||||
if ($getCheckinMac) {
|
||||
$list->transform(function (User $user) use ($getCheckinMac) {
|
||||
if($getCheckinMac){
|
||||
if ($getCheckinMac) {
|
||||
$user->checkin_macs = UserCheckinMac::select(['id', 'mac', 'remark'])->whereUserid($user->userid)->orderBy('id')->get();
|
||||
}
|
||||
return $user;
|
||||
@@ -1100,10 +1101,17 @@ class UsersController extends AbstractController
|
||||
];
|
||||
$row = UmengAlias::where($inArray);
|
||||
if ($row->exists()) {
|
||||
$row->update(['updated_at' => Carbon::now()]);
|
||||
$row->update([
|
||||
'ua' => $data['userAgent'],
|
||||
'device' => $data['deviceModel'],
|
||||
'updated_at' => Carbon::now()
|
||||
]);
|
||||
return Base::retSuccess('别名已存在');
|
||||
}
|
||||
$row = UmengAlias::createInstance($inArray);
|
||||
$row = UmengAlias::createInstance(array_merge($inArray, [
|
||||
'ua' => $data['userAgent'],
|
||||
'device' => $data['deviceModel'],
|
||||
]));
|
||||
if ($row->save()) {
|
||||
return Base::retSuccess('添加成功');
|
||||
} else {
|
||||
@@ -1135,17 +1143,17 @@ class UsersController extends AbstractController
|
||||
public function meeting__open()
|
||||
{
|
||||
$type = trim(Request::input('type'));
|
||||
$meetingid = trim(Request::input('meetingid'));
|
||||
$meetingid = str_replace(' ', '', trim(Request::input('meetingid')));
|
||||
$name = trim(Request::input('name'));
|
||||
$userids = Request::input('userids');
|
||||
$sharekey = trim(Request::input('sharekey'));
|
||||
$username = trim(Request::input('username'));
|
||||
$user = null;
|
||||
if(!empty($sharekey) && $type === 'join'){
|
||||
if(!Meeting::getShareInfo($sharekey)){
|
||||
if (!empty($sharekey) && $type === 'join') {
|
||||
if (!Meeting::getShareInfo($sharekey)) {
|
||||
return Base::retError('分享链接已过期');
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
$user = User::auth();
|
||||
}
|
||||
$isCreate = false;
|
||||
@@ -1155,6 +1163,11 @@ class UsersController extends AbstractController
|
||||
if (empty($meeting)) {
|
||||
return Base::retError('频道ID不存在');
|
||||
}
|
||||
if ($meeting->end_at) {
|
||||
return Base::retError('会议已结束');
|
||||
}
|
||||
$meeting->updated_at = Carbon::now();
|
||||
$meeting->save();
|
||||
} elseif ($type === 'create') {
|
||||
$meetingid = strtoupper(Base::generatePassword(11, 1));
|
||||
$name = $name ?: "{$user?->nickname} 发起的会议";
|
||||
@@ -1179,9 +1192,9 @@ class UsersController extends AbstractController
|
||||
if (empty($meetingSetting['appid']) || empty($meetingSetting['app_certificate'])) {
|
||||
return Base::retError('会议功能配置错误,请联系管理员');
|
||||
}
|
||||
$uid = intval(str_pad(Base::generatePassword(4,1), 9, 8, STR_PAD_LEFT));
|
||||
if($user){
|
||||
$uid = intval(str_pad(Base::generatePassword(5,1), 6, 9, STR_PAD_LEFT).$user->userid);
|
||||
$uid = intval(str_pad(Base::generatePassword(4, 1), 9, 8, STR_PAD_LEFT));
|
||||
if ($user) {
|
||||
$uid = intval(str_pad(Base::generatePassword(5, 1), 6, 9, STR_PAD_LEFT) . $user->userid);
|
||||
}
|
||||
try {
|
||||
$service = new AgoraTokenGenerator($meetingSetting['appid'], $meetingSetting['app_certificate'], $meeting->channel, $uid);
|
||||
@@ -1212,7 +1225,7 @@ class UsersController extends AbstractController
|
||||
//
|
||||
$data['appid'] = $meetingSetting['appid'];
|
||||
$data['uid'] = $uid;
|
||||
$data['userimg'] = $sharekey ? Base::fillUrl('avatar/'.$username.'.png') : $user?->userimg;
|
||||
$data['userimg'] = $sharekey ? Base::fillUrl('avatar/' . $username . '.png') : $user?->userimg;
|
||||
$data['nickname'] = $sharekey ? $username : $user?->nickname;
|
||||
$data['token'] = $token;
|
||||
$data['msgs'] = $msgs;
|
||||
@@ -1241,7 +1254,7 @@ class UsersController extends AbstractController
|
||||
{
|
||||
$meetingid = trim(Request::input('meetingid'));
|
||||
$sharekey = trim(Request::input('sharekey'));
|
||||
if(empty($sharekey) || !Meeting::getShareInfo($sharekey)){
|
||||
if (empty($sharekey) || !Meeting::getShareInfo($sharekey)) {
|
||||
User::auth();
|
||||
}
|
||||
$meeting = Meeting::whereMeetingid($meetingid)->first();
|
||||
@@ -1962,7 +1975,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if($type == 'file'){
|
||||
if ($type == 'file') {
|
||||
$lists[] = [
|
||||
'type' => 'children',
|
||||
'url' => Base::fillUrl("api/users/share/list") . "?pid=0",
|
||||
@@ -2002,4 +2015,176 @@ class UsersController extends AbstractController
|
||||
// 返回
|
||||
return Base::retSuccess('success', $lists);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/annual/report 34. 年度报告
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup users
|
||||
* @apiName annual__report
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function annual__report()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
global $_A;
|
||||
if (!isset($_A["__annual__report_".$user->userid])) {
|
||||
$year = '2023';
|
||||
$time = '2300-01-01 00:00:01';
|
||||
$prefix = \DB::getTablePrefix();
|
||||
$hireTimestamp = strtotime($user->created_at);
|
||||
DB::statement("SET SQL_MODE=''");
|
||||
|
||||
// 我的任务
|
||||
$taskDb = DB::table('project_tasks as t')
|
||||
->join('project_task_users as tu', 't.id', '=', 'tu.task_id')
|
||||
->where('tu.owner', 1)
|
||||
->whereYear('t.created_at', $year)
|
||||
->where('tu.userid', $user->userid);
|
||||
|
||||
// 我的任务 - 时长(分钟)
|
||||
$durationTaskDb = $taskDb->clone()
|
||||
->selectRaw("
|
||||
{$prefix}t.id,
|
||||
{$prefix}t.flow_item_name,
|
||||
{$prefix}t.name as task_name,
|
||||
{$prefix}p.name as project_name,
|
||||
{$prefix}c.name as project_column_name,
|
||||
{$prefix}t.start_at,
|
||||
{$prefix}t.end_at,
|
||||
{$prefix}t.complete_at,
|
||||
{$prefix}t.created_at,
|
||||
ifnull(TIMESTAMPDIFF(MINUTE, {$prefix}t.start_at, {$prefix}t.complete_at), 0) as duration
|
||||
")
|
||||
->leftJoin('projects as p', 'p.id', '=', 't.project_id')
|
||||
->leftJoin('project_columns as c', 'c.id', '=', 't.column_id')
|
||||
->whereNotNull('t.start_at')
|
||||
->whereNotNull('t.complete_at');
|
||||
|
||||
// 最多聊天用户
|
||||
$longestChat = DB::table('web_socket_dialogs as d')
|
||||
->selectRaw("
|
||||
{$prefix}d.id,
|
||||
{$prefix}d.name as dialog_name,
|
||||
{$prefix}d.type as dialog_type,
|
||||
{$prefix}d.group_type as dialog_group_type,
|
||||
{$prefix}m.chat_num,
|
||||
{$prefix}u.userid,
|
||||
{$prefix}u.email as user_email,
|
||||
{$prefix}u.nickname as user_nickname,
|
||||
ifnull({$prefix}d.avatar, {$prefix}u.userimg) as avatar
|
||||
")
|
||||
->leftJoinSub(function ($query) use ($user, $year) {
|
||||
$query->select('web_socket_dialog_msgs.dialog_id', DB::raw('count(*) as chat_num'))
|
||||
->from('web_socket_dialog_msgs')
|
||||
->where('web_socket_dialog_msgs.userid', $user->userid)
|
||||
->whereYear('web_socket_dialog_msgs.created_at', $year)
|
||||
->groupBy('web_socket_dialog_msgs.dialog_id');
|
||||
}, 'm', 'm.dialog_id', '=', 'd.id')
|
||||
->leftJoin('web_socket_dialog_users as du', function ($query) use ($user) {
|
||||
$query->on('d.id', '=', 'du.dialog_id');
|
||||
$query->where('du.userid', '!=', $user->userid);
|
||||
$query->where('d.type', 'user');
|
||||
})
|
||||
->leftJoin('users as u', 'du.userid', '=', 'u.userid')
|
||||
->where('d.type', '!=', 'user')
|
||||
->orWhere('u.bot', 0)
|
||||
->orderByDesc('m.chat_num')
|
||||
->first();
|
||||
if (!empty($longestChat)) {
|
||||
if ($longestChat->avatar) {
|
||||
$longestChat->avatar = url($longestChat->avatar);
|
||||
} else if ($longestChat->dialog_type == 'user') {
|
||||
$longestChat->avatar = User::getAvatar($longestChat->userid, $longestChat->avatar, $longestChat->user_email, $longestChat->user_nickname);
|
||||
} else {
|
||||
$longestChat->avatar = match ($longestChat->dialog_group_type) {
|
||||
'department' => url("images/avatar/default_group_department.png"),
|
||||
'project' => url("images/avatar/default_group_project.png"),
|
||||
'task' => url("images/avatar/default_group_task.png"),
|
||||
default => url("images/avatar/default_group_people.png"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 最晚在线时间
|
||||
$timezone = config('app.timezone');
|
||||
$latestOnline = UserCheckinRecord::whereUserid($user->userid)
|
||||
->whereYear(DB::raw('from_unixtime(report_time)'), $year)
|
||||
->orderByRaw("TIME_FORMAT(DATE_ADD(CONVERT_TZ(from_unixtime(report_time), 'UTC', '$timezone'), INTERVAL 18 HOUR), '%H%i%s') desc")
|
||||
->first();
|
||||
|
||||
//
|
||||
$_A["__annual__report_".$user->userid] = [
|
||||
// 本人信息
|
||||
'user' => [
|
||||
'userid' => $user->userid,
|
||||
'email' => $user->email,
|
||||
'nickname' => $user->nickname,
|
||||
'avatar' => User::getAvatar($user->userid, $user->userimg, $user->email, $user->nickname)
|
||||
],
|
||||
// 入职时间(年月日)
|
||||
'hire_date' => date("Y-m-d", $hireTimestamp),
|
||||
// 在职时间(天为单位)
|
||||
'tenure_days' => floor((strtotime(date('Y-m-d')) - $hireTimestamp) / (24 * 60 * 60)),
|
||||
// 最晚在线时间
|
||||
'latest_online_time' => date("Y-m-d H:i:s", $latestOnline->report_time),
|
||||
// 跟谁聊天最多(发消息的次数。可以是群、私聊、机器人除外)
|
||||
'longest_chat_user' => $longestChat,
|
||||
// 跟所有ai机器人聊天的次数
|
||||
'chat_al_num' => DB::table('web_socket_dialog_msgs as m')
|
||||
->join('web_socket_dialogs as d', 'd.id', '=', 'm.dialog_id')
|
||||
->join('web_socket_dialog_users as du', 'd.id', '=', 'du.dialog_id')
|
||||
->join('users as u', 'du.userid', '=', 'u.userid')
|
||||
->where('u.email', 'like', "%ai-%")
|
||||
->where('u.bot', 1)
|
||||
->where('m.userid', $user->userid)
|
||||
->whereYear('m.created_at', $year)
|
||||
->count(),
|
||||
// 文件创建数量
|
||||
'file_created_num' => File::whereCreatedId($user->userid)->whereYear('created_at', $year)->count(),
|
||||
// 参与过的项目
|
||||
'projects' => DB::table('projects as p')
|
||||
->select('p.id', 'p.name')
|
||||
->join('project_users as pu', 'p.id', '=', 'pu.project_id')
|
||||
->join('project_task_users as ptu', 'p.id', '=', 'ptu.project_id')
|
||||
->where(function($query) use ($user,$year) {
|
||||
$query->where('pu.userid', $user->userid);
|
||||
$query->whereYear('pu.created_at', $year);
|
||||
})
|
||||
->orWhere(function($query) use ($user,$year) {
|
||||
$query->where('ptu.userid', $user->userid);
|
||||
$query->whereYear('ptu.created_at', $year);
|
||||
})
|
||||
->groupBy('p.id')
|
||||
->take(100)
|
||||
->get(),
|
||||
// 任务统计
|
||||
'tasks' => [
|
||||
// 总数量
|
||||
'total' => $taskDb->count(),
|
||||
// 完成数量
|
||||
'completed' => $taskDb->clone()->whereNotNUll('t.complete_at')->count(),
|
||||
// 超时数量
|
||||
'overtime' => $taskDb->clone()->whereRaw("ifnull({$prefix}t.complete_at,'$time') > ifnull({$prefix}t.end_at,'$time')")->count(),
|
||||
// 做得最久的任务
|
||||
'longest_task' => $durationTaskDb->clone()->orderByDesc('duration')->first(),
|
||||
// 做得最快的任务
|
||||
'fastest_task' => $durationTaskDb->clone()->orderBy('duration')->first(),
|
||||
// 每个月完成多少个任务
|
||||
'month_completed_task' => $taskDb->clone()
|
||||
->selectRaw("MONTH({$prefix}t.complete_at) AS month, COUNT({$prefix}t.id) AS num")
|
||||
->whereNotNUll('t.complete_at')
|
||||
->whereYear('t.complete_at', $year)
|
||||
->groupBy('month')
|
||||
->get()
|
||||
]
|
||||
];
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('success', $_A["__annual__report_".$user->userid]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,20 +7,22 @@ use Cache;
|
||||
use Request;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use App\Module\Doo;
|
||||
use App\Models\File;
|
||||
use App\Module\Base;
|
||||
use App\Tasks\LoopTask;
|
||||
use App\Module\Extranet;
|
||||
use App\Tasks\AppPushTask;
|
||||
use App\Module\RandomColor;
|
||||
use App\Tasks\LoopTask;
|
||||
use App\Tasks\AppPushTask;
|
||||
use App\Tasks\JokeSoupTask;
|
||||
use App\Tasks\DeleteTmpTask;
|
||||
use App\Tasks\EmailNoticeTask;
|
||||
use App\Tasks\AutoArchivedTask;
|
||||
use App\Tasks\DeleteBotMsgTask;
|
||||
use App\Tasks\CheckinRemindTask;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use App\Tasks\CloseMeetingRoomTask;
|
||||
use App\Tasks\UnclaimedTaskRemindTask;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use LasseRafn\InitialAvatarGenerator\InitialAvatar;
|
||||
|
||||
|
||||
@@ -37,9 +39,8 @@ class IndexController extends InvokeController
|
||||
if ($action) {
|
||||
$app .= "__" . $action;
|
||||
}
|
||||
if ($app === 'manifest.txt') {
|
||||
$app = 'manifest';
|
||||
$child = 'txt';
|
||||
if ($app == 'default') {
|
||||
return '';
|
||||
}
|
||||
if (!method_exists($this, $app)) {
|
||||
$app = method_exists($this, $method) ? $method : 'main';
|
||||
@@ -68,49 +69,7 @@ class IndexController extends InvokeController
|
||||
'version' => Base::getVersion(),
|
||||
'style' => $style,
|
||||
'script' => $script,
|
||||
])->header('Link', "<" . url('manifest.txt') . ">; rel=\"prefetch\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Manifest
|
||||
* @param $child
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response|string
|
||||
*/
|
||||
public function manifest($child = '')
|
||||
{
|
||||
if (empty($child)) {
|
||||
$murl = url('manifest.txt');
|
||||
return response($murl)->header('Link', "<{$murl}>; rel=\"prefetch\"");
|
||||
}
|
||||
$array = [
|
||||
"office/web-apps/apps/api/documents/api.js?hash=" . Base::getVersion(),
|
||||
"office/7.5.1-23/web-apps/vendor/requirejs/require.js",
|
||||
"office/7.5.1-23/web-apps/apps/api/documents/api.js",
|
||||
"office/7.5.1-23/sdkjs/common/AllFonts.js",
|
||||
"office/7.5.1-23/web-apps/vendor/xregexp/xregexp-all-min.js",
|
||||
"office/7.5.1-23/web-apps/vendor/sockjs/sockjs.min.js",
|
||||
"office/7.5.1-23/web-apps/vendor/jszip/jszip.min.js",
|
||||
"office/7.5.1-23/web-apps/vendor/jszip-utils/jszip-utils.min.js",
|
||||
"office/7.5.1-23/sdkjs/common/libfont/wasm/fonts.js",
|
||||
"office/7.5.1-23/sdkjs/common/Charts/ChartStyles.js",
|
||||
"office/7.5.1-23/sdkjs/slide/themes//themes.js",
|
||||
|
||||
"office/7.5.1-23/web-apps/apps/presentationeditor/main/app.js",
|
||||
"office/7.5.1-23/sdkjs/slide/sdk-all-min.js",
|
||||
"office/7.5.1-23/sdkjs/slide/sdk-all.js",
|
||||
|
||||
"office/7.5.1-23/web-apps/apps/documenteditor/main/app.js",
|
||||
"office/7.5.1-23/sdkjs/word/sdk-all-min.js",
|
||||
"office/7.5.1-23/sdkjs/word/sdk-all.js",
|
||||
|
||||
"office/7.5.1-23/web-apps/apps/spreadsheeteditor/main/app.js",
|
||||
"office/7.5.1-23/sdkjs/cell/sdk-all-min.js",
|
||||
"office/7.5.1-23/sdkjs/cell/sdk-all.js",
|
||||
];
|
||||
foreach ($array as &$item) {
|
||||
$item = url($item);
|
||||
}
|
||||
return implode(PHP_EOL, $array);
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,6 +166,8 @@ class IndexController extends InvokeController
|
||||
Task::deliver(new JokeSoupTask());
|
||||
// 未领取任务通知
|
||||
Task::deliver(new UnclaimedTaskRemindTask());
|
||||
// 关闭会议室
|
||||
Task::deliver(new CloseMeetingRoomTask());
|
||||
|
||||
return "success";
|
||||
}
|
||||
@@ -217,6 +178,7 @@ class IndexController extends InvokeController
|
||||
public function desktop__publish($name = '')
|
||||
{
|
||||
$publishVersion = Request::header('publish-version');
|
||||
$fileNum = Request::get('file_num', 1);
|
||||
$latestFile = public_path("uploads/desktop/latest");
|
||||
$latestVersion = file_exists($latestFile) ? trim(file_get_contents($latestFile)) : "0.0.1";
|
||||
if (strtolower($name) === 'latest') {
|
||||
@@ -224,6 +186,7 @@ class IndexController extends InvokeController
|
||||
}
|
||||
// 上传
|
||||
if (preg_match("/^\d+\.\d+\.\d+$/", $publishVersion)) {
|
||||
$uploadSuccessFileNum = (int)Cache::get($publishVersion, 0);
|
||||
$publishKey = Request::header('publish-key');
|
||||
if ($publishKey !== env('APP_KEY')) {
|
||||
return Base::retError("key error");
|
||||
@@ -238,6 +201,20 @@ class IndexController extends InvokeController
|
||||
]);
|
||||
if (Base::isSuccess($res)) {
|
||||
file_put_contents($latestFile, $publishVersion);
|
||||
$uploadSuccessFileNum = $uploadSuccessFileNum + 1;
|
||||
Cache::set($publishVersion, $uploadSuccessFileNum, 7200);
|
||||
}
|
||||
if ($uploadSuccessFileNum >= $fileNum){
|
||||
$directoryPath = public_path("uploads/desktop");
|
||||
$files = array_filter(scandir($directoryPath), function($file) use($directoryPath) {
|
||||
return preg_match("/^\d+\.\d+\.\d+$/", $file) && is_dir($directoryPath . '/' . $file) && $file != '.' && $file != '..';
|
||||
});
|
||||
sort($files);
|
||||
foreach ($files as $key => $file) {
|
||||
if ($file != $publishVersion && $key < count($files) - 2) {
|
||||
Base::deleteDirAndFile($directoryPath . '/' . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
@@ -249,14 +226,15 @@ class IndexController extends InvokeController
|
||||
$lists = Base::readDir($dirPath);
|
||||
$files = [];
|
||||
foreach ($lists as $file) {
|
||||
if (str_ends_with($file, '.yml') || str_ends_with($file, '.yaml')) {
|
||||
if (str_ends_with($file, '.yml') || str_ends_with($file, '.yaml') || str_ends_with($file, '.blockmap')) {
|
||||
continue;
|
||||
}
|
||||
$fileName = Base::leftDelete($file, $dirPath);
|
||||
$fileSize = filesize($file);
|
||||
$files[] = [
|
||||
'name' => substr($fileName, 1),
|
||||
'time' => date("Y-m-d H:i:s", filemtime($file)),
|
||||
'size' => Base::readableBytes(filesize($file)),
|
||||
'size' => $fileSize > 0 ? Base::readableBytes($fileSize) : 0,
|
||||
'url' => Base::fillUrl($path . $fileName),
|
||||
];
|
||||
}
|
||||
@@ -273,10 +251,11 @@ class IndexController extends InvokeController
|
||||
continue;
|
||||
}
|
||||
$fileName = Base::leftDelete($file, $dirPath);
|
||||
$fileSize = filesize($file);
|
||||
$apkFile = [
|
||||
'name' => substr($fileName, 1),
|
||||
'time' => date("Y-m-d H:i:s", filemtime($file)),
|
||||
'size' => Base::readableBytes(filesize($file)),
|
||||
'size' => $fileSize > 0 ? Base::readableBytes($fileSize) : 0,
|
||||
'url' => Base::fillUrl($path . $fileName),
|
||||
];
|
||||
}
|
||||
@@ -322,48 +301,89 @@ class IndexController extends InvokeController
|
||||
$path = Arr::get($data, 'path');
|
||||
$file = public_path($path);
|
||||
// 防止 ../ 穿越获取到系统文件
|
||||
if (strpos(realpath($file), public_path()) !== 0) {
|
||||
return abort(404);
|
||||
if (!str_starts_with(realpath($file), public_path())) {
|
||||
abort(404);
|
||||
}
|
||||
//
|
||||
if (file_exists($file)) {
|
||||
parse_str($data['query'], $query);
|
||||
$name = Arr::get($query, 'name');
|
||||
$ext = strtolower(Arr::get($query, 'ext'));
|
||||
$userAgent = strtolower(Request::server('HTTP_USER_AGENT'));
|
||||
if ($ext === 'pdf'
|
||||
&& (str_contains($userAgent, 'electron') || str_contains($userAgent, 'chrome'))) {
|
||||
if (!file_exists($file)) {
|
||||
abort(404);
|
||||
}
|
||||
//
|
||||
parse_str($data['query'], $query);
|
||||
$name = Arr::get($query, 'name');
|
||||
$ext = strtolower(Arr::get($query, 'ext'));
|
||||
$userAgent = strtolower(Request::server('HTTP_USER_AGENT'));
|
||||
if ($ext === 'pdf') {
|
||||
// 文件超过 10m 不支持在线预览,提示下载
|
||||
if (filesize($file) > 10 * 1024 * 1024) {
|
||||
return view('download', [
|
||||
'name' => $name,
|
||||
'size' => Base::readableBytes(filesize($file)),
|
||||
'url' => Base::fillUrl($path),
|
||||
'button' => Doo::translate('点击下载'),
|
||||
]);
|
||||
}
|
||||
// 浏览器类型
|
||||
$browser = 'none';
|
||||
if (str_contains($userAgent, 'chrome') || str_contains($userAgent, 'android_kuaifan_eeui')) {
|
||||
$browser = str_contains($userAgent, 'android_kuaifan_eeui') ? 'android-mobile' : 'chrome-desktop';
|
||||
} elseif (str_contains($userAgent, 'safari') || str_contains($userAgent, 'ios_kuaifan_eeui')) {
|
||||
$browser = str_contains($userAgent, 'ios_kuaifan_eeui') ? 'safari-mobile' : 'safari-desktop';
|
||||
}
|
||||
// electron 直接在线预览查看
|
||||
if (str_contains($userAgent, 'electron') || str_contains($browser, 'desktop')) {
|
||||
return Response::download($file, $name, [
|
||||
'Content-Type' => 'application/pdf'
|
||||
], 'inline');
|
||||
}
|
||||
//
|
||||
if (in_array($ext, File::localExt)) {
|
||||
$url = Base::fillUrl($path);
|
||||
} else {
|
||||
$url = 'http://' . env('APP_IPPR') . '.3/' . $path;
|
||||
// EEUI App 直接在线预览查看
|
||||
if (str_contains($userAgent, 'eeui') && Base::judgeClientVersion("0.34.47")) {
|
||||
if ($browser === 'safari-mobile') {
|
||||
$redirectUrl = Base::fillUrl($path);
|
||||
return <<<EOF
|
||||
<script>
|
||||
window.top.postMessage({
|
||||
action: "eeuiAppSendMessage",
|
||||
data: [
|
||||
{
|
||||
action: 'setPageData',
|
||||
data: {
|
||||
showProgress: true,
|
||||
titleFixed: true,
|
||||
urlFixed: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
action: 'createTarget',
|
||||
url: "{$redirectUrl}",
|
||||
}
|
||||
]
|
||||
}, "*")
|
||||
</script>
|
||||
EOF;
|
||||
}
|
||||
}
|
||||
if ($ext !== 'pdf') {
|
||||
$url = Base::urlAddparameter($url, [
|
||||
'fullfilename' => $name . '.' . $ext
|
||||
]);
|
||||
}
|
||||
$toUrl = Base::fillUrl("fileview/onlinePreview?url=" . urlencode(base64_encode($url)));
|
||||
return Redirect::to($toUrl, 301);
|
||||
}
|
||||
return abort(404);
|
||||
//
|
||||
if (in_array($ext, File::localExt)) {
|
||||
$url = Base::fillUrl($path);
|
||||
} else {
|
||||
$url = 'http://' . env('APP_IPPR') . '.3/' . $path;
|
||||
}
|
||||
$url = Base::urlAddparameter($url, [
|
||||
'fullfilename' => Base::rightDelete($name, '.' . $ext) . '_' . filemtime($file) . '.' . $ext
|
||||
]);
|
||||
$redirectUrl = Base::fillUrl("fileview/onlinePreview?url=" . urlencode(base64_encode($url)));
|
||||
return Redirect::to($redirectUrl, 301);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置语言和皮肤
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
* 保存配置 (todo 已废弃)
|
||||
* @return string
|
||||
*/
|
||||
public function setting__theme_language()
|
||||
public function storage__synch()
|
||||
{
|
||||
return view('setting', [
|
||||
'theme' => Request::input('theme'),
|
||||
'language' => Request::input('language')
|
||||
]);
|
||||
return '<!-- Deprecated -->';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,9 +11,15 @@ namespace App\Models;
|
||||
* @property int|null $msg_id 消息ID
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ApproveProcMsg newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ApproveProcMsg newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ApproveProcMsg query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ApproveProcMsg whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ApproveProcMsg whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ApproveProcMsg whereMsgId($value)
|
||||
|
||||
@@ -12,9 +12,15 @@ use Carbon\Carbon;
|
||||
* @property int|null $did 删除的数据ID
|
||||
* @property int|null $userid 关系会员ID
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Deleted newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Deleted newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Deleted query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Deleted whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Deleted whereDid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Deleted whereId($value)
|
||||
|
||||
@@ -28,10 +28,16 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File whereCid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File whereCreatedId($value)
|
||||
@@ -190,9 +196,10 @@ class File extends AbstractModel
|
||||
* @param user $user
|
||||
* @param int $pid
|
||||
* @param string $webkitRelativePath
|
||||
* @param bool $overwrite
|
||||
* @return array
|
||||
*/
|
||||
public function contentUpload($user, int $pid, $webkitRelativePath)
|
||||
public function contentUpload($user, int $pid, $webkitRelativePath, $overwrite = false)
|
||||
{
|
||||
$userid = $user->userid;
|
||||
if ($pid > 0) {
|
||||
@@ -283,17 +290,25 @@ class File extends AbstractModel
|
||||
if ($data['ext'] == 'markdown') {
|
||||
$data['ext'] = 'md';
|
||||
}
|
||||
$file = File::createInstance([
|
||||
$file = null;
|
||||
$params = [
|
||||
'pid' => $pid,
|
||||
'name' => Base::rightDelete($data['name'], '.' . $data['ext']),
|
||||
'type' => $type,
|
||||
'ext' => $data['ext'],
|
||||
'userid' => $userid,
|
||||
'created_id' => $user->userid,
|
||||
]);
|
||||
$file->handleDuplicateName();
|
||||
];
|
||||
if ($overwrite) {
|
||||
$file = self::wherePid($params['pid'])->whereExt($params['ext'])->whereName($params['name'])->first();
|
||||
}
|
||||
if (!$file) {
|
||||
$overwrite = false;
|
||||
$file = File::createInstance($params);
|
||||
$file->handleDuplicateName();
|
||||
}
|
||||
// 开始创建
|
||||
return AbstractModel::transaction(function () use ($addItem, $webkitRelativePath, $type, $user, $data, $file) {
|
||||
return AbstractModel::transaction(function () use ($overwrite, $addItem, $webkitRelativePath, $type, $user, $data, $file) {
|
||||
$file->size = $data['size'] * 1024;
|
||||
$file->saveBeforePP();
|
||||
//
|
||||
@@ -321,11 +336,12 @@ class File extends AbstractModel
|
||||
$tmpRow->pushMsg('add', $tmpRow);
|
||||
//
|
||||
$data = File::handleImageUrl($tmpRow->toArray());
|
||||
$data['full_name'] = $webkitRelativePath ?: $data['name'];
|
||||
$data['full_name'] = $webkitRelativePath ?: ($data['name'] . '.' . $data['ext']);
|
||||
$data['overwrite'] = $overwrite ? 1 : 0;
|
||||
//
|
||||
$addItem[] = $data;
|
||||
|
||||
return ['data'=>$data,'addItem'=>$addItem];
|
||||
return ['data' => $data, 'addItem' => $addItem];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,16 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileContent newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileContent newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileContent onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileContent query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileContent whereContent($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileContent whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileContent whereDeletedAt($value)
|
||||
@@ -70,7 +76,7 @@ class FileContent extends AbstractModel
|
||||
'name' => $name,
|
||||
'ext' => $fileExt
|
||||
]));
|
||||
return Base::fillUrl("online/preview/{$name}?key={$key}");
|
||||
return Base::fillUrl("online/preview/{$name}?key={$key}&version=" . Base::getVersion() . "&__=" . Base::msecTime());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,16 +8,22 @@ use App\Module\Base;
|
||||
* App\Models\FileLink
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $file_id 项目ID
|
||||
* @property int|null $file_id 文件ID
|
||||
* @property int|null $num 累计访问
|
||||
* @property string|null $code 链接码
|
||||
* @property int|null $userid 会员ID
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\File|null $file
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink whereCode($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink whereFileId($value)
|
||||
|
||||
@@ -12,9 +12,15 @@ namespace App\Models;
|
||||
* @property int|null $permission 权限:0只读,1读写
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileUser newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileUser newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileUser query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileUser whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileUser whereFileId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileUser whereId($value)
|
||||
|
||||
@@ -18,9 +18,15 @@ use Illuminate\Support\Carbon;
|
||||
* @property Carbon|null $updated_at
|
||||
* @property string|null $end_at
|
||||
* @property Carbon|null $deleted_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Meeting newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Meeting newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Meeting query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Meeting whereChannel($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Meeting whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Meeting whereDeletedAt($value)
|
||||
@@ -44,12 +50,12 @@ class Meeting extends AbstractModel
|
||||
public function getShareLink()
|
||||
{
|
||||
$code = base64_encode("{$this->meetingid}" . Base::generatePassword());
|
||||
Cache::put(self::CACHE_KEY.'_'.$code, [
|
||||
Cache::put(self::CACHE_KEY . '_' . $code, [
|
||||
'id' => $this->id,
|
||||
'meetingid' => $this->meetingid,
|
||||
'channel' => $this->channel,
|
||||
], Carbon::now()->addHours(self::CACHE_EXPIRED_TIME));
|
||||
return Base::fillUrl("meeting/{$this->meetingid}/".$code);
|
||||
return Base::fillUrl("meeting/{$this->meetingid}/" . $code);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,19 +64,19 @@ class Meeting extends AbstractModel
|
||||
*/
|
||||
public static function getShareInfo($code)
|
||||
{
|
||||
if(Cache::has(self::CACHE_KEY.'_'.$code)){
|
||||
return Cache::get(self::CACHE_KEY.'_'.$code);
|
||||
if (Cache::has(self::CACHE_KEY . '_' . $code)) {
|
||||
return Cache::get(self::CACHE_KEY . '_' . $code);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存访客信息
|
||||
* @return mixed
|
||||
* @return void
|
||||
*/
|
||||
public static function setTouristInfo($data)
|
||||
{
|
||||
Cache::put(Meeting::CACHE_KEY.'_'.$data['uid'], [
|
||||
Cache::put(Meeting::CACHE_KEY . '_' . $data['uid'], [
|
||||
'uid' => $data['uid'],
|
||||
'userimg' => $data['userimg'],
|
||||
'nickname' => $data['nickname'],
|
||||
@@ -83,8 +89,8 @@ class Meeting extends AbstractModel
|
||||
*/
|
||||
public static function getTouristInfo($touristId)
|
||||
{
|
||||
if(Cache::has(Meeting::CACHE_KEY.'_'.$touristId)){
|
||||
return Cache::get(Meeting::CACHE_KEY.'_'.$touristId);
|
||||
if (Cache::has(Meeting::CACHE_KEY . '_' . $touristId)) {
|
||||
return Cache::get(Meeting::CACHE_KEY . '_' . $touristId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
34
app/Models/MeetingMsg.php
Normal file
34
app/Models/MeetingMsg.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\MeetingMsg
|
||||
*
|
||||
* @property int $id
|
||||
* @property string|null $meetingid 会议ID
|
||||
* @property int|null $dialog_id 对话ID
|
||||
* @property int|null $msg_id 消息ID
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|MeetingMsg newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|MeetingMsg newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|MeetingMsg query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|MeetingMsg whereDialogId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|MeetingMsg whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|MeetingMsg whereMeetingid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|MeetingMsg whereMsgId($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class MeetingMsg extends AbstractModel
|
||||
{
|
||||
function __construct(array $attributes = [])
|
||||
{
|
||||
parent::__construct($attributes);
|
||||
$this->timestamps = false;
|
||||
}
|
||||
}
|
||||
@@ -36,10 +36,16 @@ use Request;
|
||||
* @property-read int|null $project_user_count
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project allData($userid = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project authData($userid = null, $owner = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project whereArchivedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project whereArchivedUserid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project whereCreatedAt($value)
|
||||
|
||||
@@ -22,10 +22,16 @@ use Request;
|
||||
* @property-read \App\Models\Project|null $project
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ProjectTask> $projectTask
|
||||
* @property-read int|null $project_task_count
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn whereColor($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectColumn whereDeletedAt($value)
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Module\Base;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectFlow
|
||||
*
|
||||
@@ -14,9 +12,15 @@ use App\Module\Base;
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ProjectFlowItem> $projectFlowItem
|
||||
* @property-read int|null $project_flow_item_count
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlow newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlow newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlow query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlow whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlow whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlow whereName($value)
|
||||
|
||||
@@ -13,7 +13,7 @@ use App\Module\Base;
|
||||
* @property string|null $name 名称
|
||||
* @property string|null $status 状态
|
||||
* @property array $turns 可流转
|
||||
* @property array $userids 自动负责人ID
|
||||
* @property array $userids 状态负责人ID
|
||||
* @property string|null $usertype 流转模式
|
||||
* @property int|null $userlimit 限制负责人
|
||||
* @property int|null $columnid 对应的项目列表
|
||||
@@ -21,9 +21,15 @@ use App\Module\Base;
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\ProjectFlow|null $projectFlow
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereColumnid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereFlowId($value)
|
||||
|
||||
@@ -13,9 +13,15 @@ namespace App\Models;
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read bool $already
|
||||
* @property-read \App\Models\Project|null $project
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite whereCode($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite whereId($value)
|
||||
|
||||
@@ -10,7 +10,7 @@ use App\Module\Base;
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property int|null $column_id 列表ID
|
||||
* @property int|null $task_id 项目ID
|
||||
* @property int|null $task_id 任务ID
|
||||
* @property int|null $userid 会员ID
|
||||
* @property string|null $detail 详细信息
|
||||
* @property array $record 记录数据
|
||||
@@ -18,9 +18,15 @@ use App\Module\Base;
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\ProjectTask|null $projectTask
|
||||
* @property-read \App\Models\User|null $user
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereColumnId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereDetail($value)
|
||||
|
||||
@@ -13,9 +13,15 @@ use App\Module\Base;
|
||||
* @property string $permissions 权限
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectPermission newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectPermission newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectPermission query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectPermission whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectPermission whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectPermission wherePermissions($value)
|
||||
|
||||
@@ -63,10 +63,16 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask allData($userid = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask authData($userid = null, $owner = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask betweenTime($start, $end, $type = 'taskTime')
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereArchivedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereArchivedFollow($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereArchivedUserid($value)
|
||||
@@ -329,13 +335,7 @@ class ProjectTask extends AbstractModel
|
||||
$query->where(function ($q1) use ($start, $end, $type) {
|
||||
switch ($type) {
|
||||
case 'createdTime':
|
||||
$q1->where(function ($q2) use ($start) {
|
||||
$q2->where('project_tasks.created_at', '>=', $start);
|
||||
})->orWhere(function ($q2) use ($end) {
|
||||
$q2->where('project_tasks.created_at', '<=', $end);
|
||||
})->orWhere(function ($q2) use ($start, $end) {
|
||||
$q2->where('project_tasks.created_at', '>', $start)->where('project_tasks.created_at', '<', $end);
|
||||
});
|
||||
$q1->where('project_tasks.created_at', '>=', $start)->where('project_tasks.created_at', '<=', $end);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1430,53 +1430,62 @@ class ProjectTask extends AbstractModel
|
||||
}
|
||||
//
|
||||
$array = [];
|
||||
if (empty($data['parent_id'])) {
|
||||
if (Arr::exists($data, 'owner') || Arr::exists($data, 'assist')) {
|
||||
$taskUser = ProjectTaskUser::select(['userid', 'owner'])->whereTaskId($data['id'])->get();
|
||||
// 负责人
|
||||
$owners = $taskUser->where('owner', 1)->pluck('userid')->toArray();
|
||||
$owners = array_intersect($userids, $owners);
|
||||
if ($owners) {
|
||||
$array[] = [
|
||||
'userid' => array_values($owners),
|
||||
'data' => array_merge($data, [
|
||||
'owner' => 1,
|
||||
'assist' => 1,
|
||||
])
|
||||
];
|
||||
}
|
||||
// 协助人
|
||||
$assists = $taskUser->where('owner', 0)->pluck('userid')->toArray();
|
||||
$assists = array_intersect($userids, $assists);
|
||||
if ($assists) {
|
||||
$array[] = [
|
||||
'userid' => array_values($assists),
|
||||
'data' => array_merge($data, [
|
||||
'owner' => 0,
|
||||
'assist' => 1,
|
||||
])
|
||||
];
|
||||
}
|
||||
// 项目成员(其他人)
|
||||
if ($data['visibility'] == 1) {
|
||||
// 全部可见
|
||||
if (Arr::exists($data, 'owner') || Arr::exists($data, 'assist')) {
|
||||
$taskUser = ProjectTaskUser::select(['userid', 'owner'])->whereTaskId($data['id'])->get();
|
||||
// 负责人
|
||||
$owners = $taskUser->where('owner', 1)->pluck('userid')->toArray();
|
||||
$owners = array_intersect($userids, $owners);
|
||||
if ($owners) {
|
||||
$array[] = [
|
||||
'userid' => array_values($owners),
|
||||
'data' => array_merge($data, [
|
||||
'owner' => 1,
|
||||
'assist' => 1,
|
||||
])
|
||||
];
|
||||
}
|
||||
// 协助人
|
||||
$assists = $taskUser->where('owner', 0)->pluck('userid')->toArray();
|
||||
$assists = array_intersect($userids, $assists);
|
||||
if ($assists) {
|
||||
$array[] = [
|
||||
'userid' => array_values($assists),
|
||||
'data' => array_merge($data, [
|
||||
'owner' => 0,
|
||||
'assist' => 1,
|
||||
])
|
||||
];
|
||||
}
|
||||
// 其他人
|
||||
switch ($data['visibility']) {
|
||||
case 1:
|
||||
// 项目人员,除了负责人、协助人项目其他人
|
||||
$userids = array_diff($userids, $owners, $assists);
|
||||
} else {
|
||||
// 指定可见
|
||||
$userids = $taskUser->pluck('userid')->toArray();
|
||||
}
|
||||
$data = array_merge($data, [
|
||||
'owner' => 0,
|
||||
'assist' => 0,
|
||||
]);
|
||||
break;
|
||||
case 2:
|
||||
// 任务人员,除了负责人、协助人
|
||||
$userids = [];
|
||||
break;
|
||||
case 3:
|
||||
// 指定成员
|
||||
$specifys = ProjectTaskVisibilityUser::select(['userid'])->whereTaskId($data['id'])->pluck('userid')->toArray();
|
||||
$userids = array_diff($specifys, $owners, $assists);
|
||||
break;
|
||||
default:
|
||||
$userids = [];
|
||||
break;
|
||||
}
|
||||
if ($userids) {
|
||||
$array[] = [
|
||||
'userid' => array_values($userids),
|
||||
'data' => array_merge($data, [
|
||||
'owner' => 0,
|
||||
'assist' => 0,
|
||||
])
|
||||
];
|
||||
}
|
||||
}
|
||||
//
|
||||
$array[] = [
|
||||
'userid' => array_values($userids),
|
||||
'data' => $data
|
||||
];
|
||||
//
|
||||
foreach ($array as $item) {
|
||||
$params = [
|
||||
'ignoreFd' => Request::header('fd'),
|
||||
|
||||
@@ -14,9 +14,15 @@ use App\Exceptions\ApiException;
|
||||
* @property string|null $content 内容
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent whereContent($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskContent whereId($value)
|
||||
|
||||
@@ -22,9 +22,15 @@ use Cache;
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read int $height
|
||||
* @property-read int $width
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFile newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFile newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFile query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFile whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFile whereDownload($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFile whereExt($value)
|
||||
|
||||
@@ -14,9 +14,15 @@ namespace App\Models;
|
||||
* @property string|null $after_flow_item_name (变化后)工作流状态名称
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereAfterFlowItemId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereAfterFlowItemName($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereBeforeFlowItemId($value)
|
||||
|
||||
@@ -17,10 +17,16 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskPushLog newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskPushLog newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskPushLog onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskPushLog query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskPushLog whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskPushLog whereDeletedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskPushLog whereId($value)
|
||||
|
||||
@@ -12,9 +12,15 @@ namespace App\Models;
|
||||
* @property string|null $color 颜色
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskTag newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskTag newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskTag query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskTag whereColor($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskTag whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskTag whereId($value)
|
||||
|
||||
@@ -14,9 +14,15 @@ namespace App\Models;
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\ProjectTask|null $projectTask
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser whereOwner($value)
|
||||
|
||||
@@ -12,9 +12,15 @@ namespace App\Models;
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\ProjectTask|null $projectTask
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskVisibilityUser newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskVisibilityUser newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskVisibilityUser query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskVisibilityUser whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskVisibilityUser whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskVisibilityUser whereProjectId($value)
|
||||
|
||||
@@ -13,9 +13,15 @@ namespace App\Models;
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\Project|null $project
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereOwner($value)
|
||||
|
||||
@@ -29,9 +29,15 @@ use JetBrains\PhpStorm\Pure;
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\User> $receivesUser
|
||||
* @property-read int|null $receives_user_count
|
||||
* @property-read \App\Models\User|null $sendUser
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static Builder|Report newModelQuery()
|
||||
* @method static Builder|Report newQuery()
|
||||
* @method static Builder|Report query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static Builder|Report whereContent($value)
|
||||
* @method static Builder|Report whereCreatedAt($value)
|
||||
* @method static Builder|Report whereId($value)
|
||||
|
||||
@@ -13,9 +13,15 @@ use Illuminate\Database\Eloquent\Model;
|
||||
* @property string|null $receive_time 接收时间
|
||||
* @property int $userid 接收人
|
||||
* @property int $read 是否已读
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereRead($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereReceiveTime($value)
|
||||
|
||||
@@ -13,9 +13,15 @@ use App\Module\Base;
|
||||
* @property string|null $setting
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Setting newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Setting newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Setting query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Setting whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Setting whereDesc($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Setting whereId($value)
|
||||
|
||||
@@ -15,10 +15,16 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|TaskWorker newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|TaskWorker newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|TaskWorker onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|TaskWorker query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|TaskWorker whereArgs($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|TaskWorker whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|TaskWorker whereDeletedAt($value)
|
||||
|
||||
@@ -11,9 +11,15 @@ namespace App\Models;
|
||||
* @property string|null $content
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Tmp newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Tmp newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Tmp query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Tmp whereContent($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Tmp whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Tmp whereId($value)
|
||||
|
||||
@@ -14,15 +14,25 @@ use Hedeqiang\UMeng\IOS;
|
||||
* @property int|null $userid 会员ID
|
||||
* @property string|null $alias 别名
|
||||
* @property string|null $platform 平台类型
|
||||
* @property string|null $device 设备类型
|
||||
* @property string|null $ua userAgent
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @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 whereId($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)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UmengAlias whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
@@ -31,6 +41,16 @@ class UmengAlias extends AbstractModel
|
||||
{
|
||||
protected $table = 'umeng_alias';
|
||||
|
||||
/**
|
||||
* 推送内容处理
|
||||
* @param $string
|
||||
* @return string
|
||||
*/
|
||||
private static function specialCharacters($string)
|
||||
{
|
||||
return str_replace(["\r\n", "\r", "\n"], '', $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推送配置
|
||||
* @return array|false
|
||||
@@ -73,9 +93,9 @@ class UmengAlias extends AbstractModel
|
||||
return false;
|
||||
}
|
||||
//
|
||||
$title = $array['title'] ?: ''; // 标题
|
||||
$subtitle = $array['subtitle'] ?: ''; // 副标题(iOS)
|
||||
$body = $array['body'] ?: ''; // 通知内容
|
||||
$title = self::specialCharacters($array['title'] ?: ''); // 标题
|
||||
$subtitle = self::specialCharacters($array['subtitle'] ?: ''); // 副标题(iOS)
|
||||
$body = self::specialCharacters($array['body'] ?: ''); // 通知内容
|
||||
$description = $array['description'] ?: 'no description'; // 描述
|
||||
$extra = is_array($array['extra']) ? $array['extra'] : []; // 额外参数
|
||||
$seconds = intval($array['seconds']) ?: 86400; // 有效时间(单位:秒)
|
||||
@@ -132,7 +152,13 @@ class UmengAlias extends AbstractModel
|
||||
'mi_activity' => 'app.eeui.umeng.activity.MfrMessageActivity',
|
||||
'policy' => [
|
||||
'expire_time' => Carbon::now()->addSeconds($seconds)->toDateTimeString(),
|
||||
]
|
||||
],
|
||||
'channel_properties' => [
|
||||
'vivo_category' => 'IM',
|
||||
'huawei_channel_importance' => 'NORMAL',
|
||||
'huawei_channel_category' => 'IM',
|
||||
'channel_fcm' => 1,
|
||||
],
|
||||
]);
|
||||
|
||||
default:
|
||||
|
||||
@@ -37,10 +37,16 @@ use Carbon\Carbon;
|
||||
* @property int|null $bot 是否机器人
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Database\Factories\UserFactory factory(...$parameters)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereAz($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereBot($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereChangepass($value)
|
||||
@@ -290,6 +296,26 @@ class User extends AbstractModel
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查发送聊天内容前必须设置昵称、电话
|
||||
* @return void
|
||||
*/
|
||||
public function checkChatInformation()
|
||||
{
|
||||
if ($this->bot) {
|
||||
return;
|
||||
}
|
||||
$chatInformation = Base::settingFind('system', 'chat_information');
|
||||
if ($chatInformation == 'required') {
|
||||
if (empty($this->getRawOriginal('nickname'))) {
|
||||
throw new ApiException('请设置昵称', [], -2);
|
||||
}
|
||||
if (empty($this->getRawOriginal('tel'))) {
|
||||
throw new ApiException('请设置联系电话', [], -3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** ***************************************************************************************** */
|
||||
/** ***************************************************************************************** */
|
||||
/** ***************************************************************************************** */
|
||||
@@ -507,6 +533,16 @@ class User extends AbstractModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 临时帐号别名
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function tempAccountAlias()
|
||||
{
|
||||
$alias = Base::settingFind('system', 'temp_account_alias');
|
||||
return $alias ?: Doo::translate("临时帐号");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头像
|
||||
* @param $userid
|
||||
@@ -539,6 +575,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-gemini@bot.system':
|
||||
return url("images/avatar/default_gemini.png");
|
||||
case 'bot-manager@bot.system':
|
||||
return url("images/avatar/default_bot.png");
|
||||
case 'meeting-alert@bot.system':
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Models;
|
||||
use App\Module\Base;
|
||||
use App\Module\Doo;
|
||||
use App\Module\Extranet;
|
||||
use App\Tasks\JokeSoupTask;
|
||||
use Cache;
|
||||
use Carbon\Carbon;
|
||||
|
||||
@@ -20,9 +21,15 @@ use Carbon\Carbon;
|
||||
* @property int|null $webhook_num 消息webhook请求次数
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserBot newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserBot newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserBot query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserBot whereBotId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserBot whereClearAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserBot whereClearDay($value)
|
||||
@@ -57,6 +64,7 @@ class UserBot extends AbstractModel
|
||||
'ai-claude' => 'Claude',
|
||||
'ai-wenxin' => '文心一言',
|
||||
'ai-qianwen' => '通义千问',
|
||||
'ai-gemini' => 'Gemini',
|
||||
'bot-manager' => '机器人管理',
|
||||
'meeting-alert' => '会议通知',
|
||||
'okr-alert' => 'OKR提醒',
|
||||
@@ -117,6 +125,7 @@ class UserBot extends AbstractModel
|
||||
'ai-openai@bot.system',
|
||||
'ai-claude@bot.system',
|
||||
'ai-wenxin@bot.system',
|
||||
'ai-gemini@bot.system',
|
||||
'ai-qianwen@bot.system' => [
|
||||
[
|
||||
'key' => '%3A.clear',
|
||||
@@ -227,8 +236,8 @@ class UserBot extends AbstractModel
|
||||
if ($checkins && $botUser = User::botGetOrCreate('check-in')) {
|
||||
$getJokeSoup = function($type) {
|
||||
$pre = $type == "up" ? "每日开心:" : "心灵鸡汤:";
|
||||
$key = $type == "up" ? "JokeSoupTask:jokes" : "JokeSoupTask:soups";
|
||||
$array = Base::json2array(Cache::get($key));
|
||||
$key = $type == "up" ? "jokes" : "soups";
|
||||
$array = Base::json2array(Cache::get(JokeSoupTask::keyName($key)));
|
||||
if ($array) {
|
||||
$item = $array[array_rand($array)];
|
||||
if ($item) {
|
||||
|
||||
@@ -15,9 +15,15 @@ use App\Module\Base;
|
||||
* @property string|null $remark 备注
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinMac newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinMac newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinMac query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinMac whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinMac whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinMac whereMac($value)
|
||||
|
||||
@@ -16,9 +16,15 @@ use App\Module\Base;
|
||||
* @property int|null $report_time 上报的时间戳
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinRecord newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinRecord newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinRecord query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinRecord whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinRecord whereDate($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserCheckinRecord whereId($value)
|
||||
|
||||
@@ -16,9 +16,15 @@ use App\Module\Base;
|
||||
* @property string $cache 会员资料缓存
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereCache($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDelete whereEmail($value)
|
||||
|
||||
@@ -14,9 +14,15 @@ use App\Exceptions\ApiException;
|
||||
* @property int|null $owner_userid 部门负责人
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDepartment newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDepartment newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDepartment query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDepartment whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDepartment whereDialogId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserDepartment whereId($value)
|
||||
|
||||
@@ -19,9 +19,15 @@ use Guanguans\Notify\Messages\EmailMessage;
|
||||
* @property int|null $type 邮件类型:1-邮箱认证,2-修改邮箱
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification whereCode($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification whereEmail($value)
|
||||
|
||||
@@ -16,9 +16,15 @@ use Guanguans\Notify\Messages\EmailMessage;
|
||||
* @property int|null $new_userid 交接人
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserTransfer newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserTransfer newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserTransfer query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserTransfer whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserTransfer whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserTransfer whereNewUserid($value)
|
||||
|
||||
@@ -13,9 +13,15 @@ namespace App\Models;
|
||||
* @property int|null $userid
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket whereFd($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket whereId($value)
|
||||
|
||||
@@ -20,29 +20,35 @@ use Illuminate\Support\Facades\DB;
|
||||
* @property string|null $group_type 聊天室类型
|
||||
* @property string|null $name 对话名称
|
||||
* @property string $avatar 头像(群)
|
||||
* @property string|null $last_at 最后消息时间
|
||||
* @property int|null $owner_id 群主用户ID
|
||||
* @property int|null $link_id 关联id
|
||||
* @property int|null $top_userid 置顶的用户ID
|
||||
* @property int|null $top_msg_id 置顶的消息ID
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\WebSocketDialogUser> $dialogUser
|
||||
* @property-read int|null $dialog_user_count
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereAvatar($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereDeletedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereGroupType($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereLastAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereLinkId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereName($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereOwnerId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereTopMsgId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereTopUserid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereType($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog withTrashed()
|
||||
@@ -81,7 +87,7 @@ class WebSocketDialog extends AbstractModel
|
||||
*/
|
||||
public static function getDialogList($userid, $updated = "", $deleted = "")
|
||||
{
|
||||
$builder = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.color', 'u.updated_at as user_at'])
|
||||
$builder = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->where('u.userid', $userid);
|
||||
if ($updated) {
|
||||
@@ -89,7 +95,7 @@ class WebSocketDialog extends AbstractModel
|
||||
}
|
||||
$list = $builder
|
||||
->orderByDesc('u.top_at')
|
||||
->orderByDesc('web_socket_dialogs.last_at')
|
||||
->orderByDesc('u.last_at')
|
||||
->paginate(Base::getPaginate(100, 50));
|
||||
$list->transform(function (WebSocketDialog $item) use ($userid) {
|
||||
return $item->formatData($userid);
|
||||
@@ -103,30 +109,70 @@ class WebSocketDialog extends AbstractModel
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未读对话列表
|
||||
* 列表外的未读对话 和 列表外的待办对话
|
||||
* @param $userid
|
||||
* @param $beforeAt
|
||||
* @param $take
|
||||
* @param $unreadAt
|
||||
* @param $todoAt
|
||||
* @return WebSocketDialog[]
|
||||
*/
|
||||
public static function getDialogUnread($userid, $beforeAt, $take = 20)
|
||||
public static function getDialogBeyond($userid, $unreadAt, $todoAt)
|
||||
{
|
||||
DB::statement("SET SQL_MODE=''");
|
||||
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.color', 'u.updated_at as user_at'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->join('web_socket_dialog_msg_reads as r', 'web_socket_dialogs.id', '=', 'r.dialog_id')
|
||||
->where('r.userid', $userid)
|
||||
->where('r.silence', 0)
|
||||
->where('r.read_at')
|
||||
->where('web_socket_dialogs.last_at', '>', $beforeAt)
|
||||
->groupBy('web_socket_dialogs.id')
|
||||
->take(min(100, $take))
|
||||
->get();
|
||||
$list->transform(function (WebSocketDialog $item) use ($userid) {
|
||||
return $item->formatData($userid);
|
||||
});
|
||||
//
|
||||
return $list;
|
||||
$ids = [];
|
||||
$array = [];
|
||||
if ($unreadAt) {
|
||||
// 未读对话
|
||||
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->join('web_socket_dialog_msg_reads as r', 'web_socket_dialogs.id', '=', 'r.dialog_id')
|
||||
->where('u.userid', $userid)
|
||||
->where('r.userid', $userid)
|
||||
->where('r.read_at')
|
||||
->where('u.last_at', '<', $unreadAt)
|
||||
->groupBy('u.dialog_id')
|
||||
->take(20)
|
||||
->get();
|
||||
$list->transform(function (WebSocketDialog $item) use ($userid, &$ids, &$array) {
|
||||
if (!in_array($item->id, $ids)) {
|
||||
$ids[] = $item->id;
|
||||
$array[] = $item->formatData($userid);
|
||||
}
|
||||
});
|
||||
// 标记未读会话
|
||||
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->where('u.userid', $userid)
|
||||
->where('u.mark_unread', 1)
|
||||
->where('u.last_at', '<', $unreadAt)
|
||||
->take(20)
|
||||
->get();
|
||||
$list->transform(function (WebSocketDialog $item) use ($userid, &$ids, &$array) {
|
||||
if (!in_array($item->id, $ids)) {
|
||||
$ids[] = $item->id;
|
||||
$array[] = $item->formatData($userid);
|
||||
}
|
||||
});
|
||||
}
|
||||
if ($todoAt) {
|
||||
// 待办会话
|
||||
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->join('web_socket_dialog_msg_todos as t', 'web_socket_dialogs.id', '=', 't.dialog_id')
|
||||
->where('u.userid', $userid)
|
||||
->where('t.userid', $userid)
|
||||
->where('t.done_at')
|
||||
->where('u.last_at', '<', $todoAt)
|
||||
->groupBy('u.dialog_id')
|
||||
->take(20)
|
||||
->get();
|
||||
$list->transform(function (WebSocketDialog $item) use ($userid, &$ids, &$array) {
|
||||
if (!in_array($item->id, $ids)) {
|
||||
$ids[] = $item->id;
|
||||
$array[] = $item->formatData($userid);
|
||||
}
|
||||
});
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
@@ -146,17 +192,23 @@ class WebSocketDialog extends AbstractModel
|
||||
};
|
||||
//
|
||||
$time = Carbon::parse($this->user_at ?? $dialogUserFun('updated_at'));
|
||||
$this->hide = $this->hide ?? $dialogUserFun('hide');
|
||||
$this->top_at = $this->top_at ?? $dialogUserFun('top_at');
|
||||
$this->last_at = $this->last_at ?? $dialogUserFun('last_at');
|
||||
$this->user_at = $time->toDateTimeString('millisecond');
|
||||
$this->user_ms = $time->valueOf();
|
||||
//
|
||||
if (isset($this->search_msg_id)) {
|
||||
// 最后消息 (搜索预览消息)
|
||||
$this->last_msg = WebSocketDialogMsg::whereDialogId($this->id)->find($this->search_msg_id);
|
||||
$this->last_at = $this->last_msg?->created_at;
|
||||
$this->last_at = $this->last_msg ? Carbon::parse($this->last_msg->created_at)->format('Y-m-d H:i:s') : null;
|
||||
} else {
|
||||
// 未读信息
|
||||
$this->generateUnread($userid, $hasData);
|
||||
if (Base::judgeClientVersion("0.34.0")) {
|
||||
$this->generateUnread($userid);
|
||||
} else {
|
||||
$this->generateUnread_03398($userid, $hasData);
|
||||
}
|
||||
// 未读标记
|
||||
$this->mark_unread = $this->mark_unread ?? $dialogUserFun('mark_unread');
|
||||
// 是否免打扰
|
||||
@@ -192,9 +244,13 @@ class WebSocketDialog extends AbstractModel
|
||||
$this->dialog_delete = 1;
|
||||
}
|
||||
$this->dialog_user = $dialog_user;
|
||||
$this->dialog_mute = Base::settingFind('system', 'user_private_chat_mute');
|
||||
break;
|
||||
case "group":
|
||||
switch ($this->group_type) {
|
||||
case 'user':
|
||||
$this->dialog_mute = Base::settingFind('system', 'user_group_chat_mute');
|
||||
break;
|
||||
case 'project':
|
||||
$this->group_info = Project::withTrashed()->select(['id', 'name', 'archived_at', 'deleted_at'])->whereDialogId($this->id)->first()?->cancelAppend()->cancelHidden();
|
||||
if ($this->group_info) {
|
||||
@@ -215,7 +271,7 @@ class WebSocketDialog extends AbstractModel
|
||||
break;
|
||||
case 'all':
|
||||
$this->name = Doo::translate('全体成员');
|
||||
$this->all_group_mute = Base::settingFind('system', 'all_group_mute');
|
||||
$this->dialog_mute = Base::settingFind('system', 'all_group_mute');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -250,10 +306,29 @@ class WebSocketDialog extends AbstractModel
|
||||
/**
|
||||
* 生成未读数据
|
||||
* @param $userid
|
||||
* @return $this
|
||||
*/
|
||||
public function generateUnread($userid)
|
||||
{
|
||||
$builder = WebSocketDialogMsgRead::whereDialogId($this->id)->whereUserid($userid)->whereReadAt(null);
|
||||
// 未读消息
|
||||
$this->unread = $builder->count();
|
||||
// 最早一条未读消息
|
||||
$this->unread_one = $this->unread > 0 ? intval($builder->clone()->orderBy('msg_id')->value('msg_id')) : 0;
|
||||
// @我的消息
|
||||
$this->mention = $this->unread > 0 ? $builder->clone()->whereMention(1)->count() : 0;
|
||||
// @我的消息(id集合)
|
||||
$this->mention_ids = $this->mention > 0 ? $builder->clone()->whereMention(1)->orderByDesc('msg_id')->take(20)->pluck('msg_id')->toArray() : [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成未读数据 // todo: 旧版兼容,后续删除
|
||||
* @param $userid
|
||||
* @param $positionData
|
||||
* @return $this
|
||||
*/
|
||||
public function generateUnread($userid, $positionData = false)
|
||||
public function generateUnread_03398($userid, $positionData = false)
|
||||
{
|
||||
$builder = WebSocketDialogMsgRead::whereDialogId($this->id)->whereUserid($userid)->whereReadAt(null);
|
||||
$this->unread = $builder->count();
|
||||
@@ -435,17 +510,37 @@ class WebSocketDialog extends AbstractModel
|
||||
*/
|
||||
public function checkMute($userid)
|
||||
{
|
||||
if ($this->group_type === 'all') {
|
||||
$allGroupMute = Base::settingFind('system', 'all_group_mute');
|
||||
switch ($allGroupMute) {
|
||||
case 'all':
|
||||
throw new ApiException('当前会话全员禁言');
|
||||
case 'user':
|
||||
if (!User::find($userid)?->isAdmin()) {
|
||||
throw new ApiException('当前会话禁言');
|
||||
$muteMsgTip = null;
|
||||
$systemConfig = Base::setting('system');
|
||||
switch ($this->type) {
|
||||
case 'user':
|
||||
if ($systemConfig['user_private_chat_mute'] === 'close') {
|
||||
$muteMsgTip = '个人会话禁言';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'group':
|
||||
if ($this->group_type === 'user') {
|
||||
if ($systemConfig['user_group_chat_mute'] === 'close') {
|
||||
$muteMsgTip = '个人群组禁言';
|
||||
}
|
||||
} elseif ($this->group_type === 'all') {
|
||||
if ($systemConfig['all_group_mute'] === 'close') {
|
||||
$muteMsgTip = '当前会话全员禁言';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ($muteMsgTip === null) {
|
||||
return;
|
||||
}
|
||||
if ($userid) {
|
||||
$user = User::find($userid);
|
||||
if ($user?->bot || $user?->isAdmin()) { // 机器人或管理员不受禁言
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new ApiException($muteMsgTip);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -503,20 +598,6 @@ class WebSocketDialog extends AbstractModel
|
||||
Task::deliver($task);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新对话最后消息时间
|
||||
* @return WebSocketDialogMsg|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|\Illuminate\Database\Query\Builder|object|null
|
||||
*/
|
||||
public function updateMsgLastAt()
|
||||
{
|
||||
$lastMsg = WebSocketDialogMsg::whereDialogId($this->id)->orderByDesc('id')->first();
|
||||
if ($lastMsg) {
|
||||
$this->last_at = $lastMsg->created_at;
|
||||
$this->save();
|
||||
}
|
||||
return $lastMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对话(同时检验对话身份)
|
||||
* @param $dialog_id
|
||||
@@ -573,7 +654,6 @@ class WebSocketDialog extends AbstractModel
|
||||
'name' => $name ?: '',
|
||||
'group_type' => $group_type,
|
||||
'owner_id' => $owner_id,
|
||||
'last_at' => in_array($group_type, ['user', 'department', 'all']) ? Carbon::now() : null,
|
||||
]);
|
||||
$dialog->save();
|
||||
foreach (is_array($userid) ? $userid : [$userid] as $value) {
|
||||
@@ -581,7 +661,8 @@ class WebSocketDialog extends AbstractModel
|
||||
WebSocketDialogUser::createInstance([
|
||||
'dialog_id' => $dialog->id,
|
||||
'userid' => $value,
|
||||
'important' => !in_array($group_type, ['user', 'all'])
|
||||
'important' => !in_array($group_type, ['user', 'all']),
|
||||
'last_at' => in_array($group_type, ['user', 'department', 'all']) ? Carbon::now() : null,
|
||||
])->save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,18 +33,21 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property int|null $reply_id 回复ID
|
||||
* @property int|null $forward_id 转发ID
|
||||
* @property int|null $forward_num 被转发多少次
|
||||
* @property int|null $forward_show 是否显示转发的来源
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @property-read \App\Models\WebSocketDialogMsg|null $forward_data
|
||||
* @property-read int|mixed $percentage
|
||||
* @property-read \App\Models\WebSocketDialogMsg|null $reply_data
|
||||
* @property-read \App\Models\WebSocketDialog|null $webSocketDialog
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDeletedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDialogId($value)
|
||||
@@ -52,7 +55,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereEmoji($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereForwardId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereForwardNum($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereForwardShow($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereKey($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereLink($value)
|
||||
@@ -78,8 +80,6 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
|
||||
protected $appends = [
|
||||
'percentage',
|
||||
'reply_data',
|
||||
'forward_data',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
@@ -107,36 +107,6 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
return $this->appendattrs['percentage'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 回复消息详情
|
||||
* @return WebSocketDialogMsg|null
|
||||
*/
|
||||
public function getReplyDataAttribute()
|
||||
{
|
||||
if (!isset($this->appendattrs['reply_data'])) {
|
||||
$this->appendattrs['reply_data'] = null;
|
||||
if ($this->reply_id > 0) {
|
||||
$this->appendattrs['reply_data'] = self::find($this->reply_id, ['id', 'userid', 'type', 'msg'])?->cancelAppend() ?: null;
|
||||
}
|
||||
}
|
||||
return $this->appendattrs['reply_data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 转发消息详情
|
||||
* @return WebSocketDialogMsg|null
|
||||
*/
|
||||
public function getForwardDataAttribute()
|
||||
{
|
||||
if (!isset($this->appendattrs['forward_data'])) {
|
||||
$this->appendattrs['forward_data'] = null;
|
||||
if ($this->forward_id > 0) {
|
||||
$this->appendattrs['forward_data'] = self::find($this->forward_id, ['id', 'userid', 'type', 'msg'])?->cancelAppend() ?: null;
|
||||
}
|
||||
}
|
||||
return $this->appendattrs['forward_data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息格式化
|
||||
* @param $value
|
||||
@@ -147,13 +117,9 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
if (is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
$value = Base::json2array($value);
|
||||
if ($this->type === 'file') {
|
||||
$value['type'] = in_array($value['ext'], ['jpg', 'jpeg', 'webp', 'png', 'gif']) ? 'img' : 'file';
|
||||
$value['path'] = Base::fillUrl($value['path']);
|
||||
$value['thumb'] = Base::fillUrl($value['thumb'] ?: Base::extIcon($value['ext']));
|
||||
} else if ($this->type === 'record') {
|
||||
$value['path'] = Base::fillUrl($value['path']);
|
||||
$value = $this->formatDataMsg($this->type, $value);
|
||||
if (isset($value['reply_data'])) {
|
||||
$value['reply_data']['msg'] = $this->formatDataMsg($value['reply_data']['type'], $value['reply_data']['msg']);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
@@ -171,6 +137,27 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
return Base::json2array($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理消息数据
|
||||
* @param $type
|
||||
* @param $msg
|
||||
* @return mixed
|
||||
*/
|
||||
private function formatDataMsg($type, $msg)
|
||||
{
|
||||
if (!is_array($msg)) {
|
||||
$msg = Base::json2array($msg);
|
||||
}
|
||||
if ($type === 'file') {
|
||||
$msg['type'] = in_array($msg['ext'], ['jpg', 'jpeg', 'webp', 'png', 'gif']) ? 'img' : 'file';
|
||||
$msg['path'] = Base::fillUrl($msg['path']);
|
||||
$msg['thumb'] = Base::fillUrl($msg['thumb'] ?: Base::extIcon($msg['ext']));
|
||||
} else if ($type === 'record') {
|
||||
$msg['path'] = Base::fillUrl($msg['path']);
|
||||
}
|
||||
return $msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取占比
|
||||
* @param bool|int $increment 是否新增阅读数
|
||||
@@ -391,15 +378,25 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
* 转发消息
|
||||
* @param array|int $dialogids
|
||||
* @param array|int $userids
|
||||
* @param User $user 发送的会员
|
||||
* @param int $showSource 是否显示原发送者信息
|
||||
* @param string $leaveMessage 转发留言
|
||||
* @param User $user 发送的会员
|
||||
* @param int $showSource 是否显示原发送者信息
|
||||
* @param string $leaveMessage 转发留言
|
||||
* @return mixed
|
||||
*/
|
||||
public function forwardMsg($dialogids, $userids, $user, $showSource = 1, $leaveMessage = '')
|
||||
{
|
||||
return AbstractModel::transaction(function() use ($dialogids, $user, $userids, $showSource, $leaveMessage) {
|
||||
$originalMsg = Base::json2array($this->getRawOriginal('msg'));
|
||||
return AbstractModel::transaction(function () use ($dialogids, $user, $userids, $showSource, $leaveMessage) {
|
||||
$msgData = Base::json2array($this->getRawOriginal('msg'));
|
||||
$forwardData = is_array($msgData['forward_data']) ? $msgData['forward_data'] : [];
|
||||
$forwardId = $forwardData['id'] ?: $this->id;
|
||||
$forwardUserid = $forwardData['userid'] ?: $this->userid;
|
||||
$msgData['forward_data'] = [
|
||||
'id' => $forwardId, // 转发的消息ID(原始)
|
||||
'userid' => $forwardUserid, // 转发的消息会员ID(原始)
|
||||
'parent_id' => $this->id, // 转发的消息ID
|
||||
'parent_userid' => $this->userid, // 转发的消息会员ID
|
||||
'show' => $showSource, // 是否显示原发送者信息
|
||||
];
|
||||
$msgs = [];
|
||||
$already = [];
|
||||
if ($dialogids) {
|
||||
@@ -407,7 +404,7 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
$dialogids = [$dialogids];
|
||||
}
|
||||
foreach ($dialogids as $dialogid) {
|
||||
$res = self::sendMsg('forward-'.( $showSource ? 1 : 0).'-'.($this->forward_id ?: $this->id), $dialogid, $this->type, $originalMsg, $user->userid);
|
||||
$res = self::sendMsg('forward-' . $forwardId, $dialogid, $this->type, $msgData, $user->userid);
|
||||
if (Base::isSuccess($res)) {
|
||||
$msgs[] = $res['data'];
|
||||
$already[] = $dialogid;
|
||||
@@ -427,7 +424,7 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
}
|
||||
$dialog = WebSocketDialog::checkUserDialog($user, $userid);
|
||||
if ($dialog && !in_array($dialog->id, $already)) {
|
||||
$res = self::sendMsg('forward-'.( $showSource ? 1 : 0).'-'.($this->forward_id ?: $this->id), $dialog->id, $this->type, $originalMsg, $user->userid);
|
||||
$res = self::sendMsg('forward-' . $forwardId, $dialog->id, $this->type, $msgData, $user->userid);
|
||||
if (Base::isSuccess($res)) {
|
||||
$msgs[] = $res['data'];
|
||||
}
|
||||
@@ -437,6 +434,9 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($msgs) > 0) {
|
||||
$this->increment('forward_num', count($msgs));
|
||||
}
|
||||
return Base::retSuccess('转发成功', [
|
||||
'msgs' => $msgs
|
||||
]);
|
||||
@@ -458,9 +458,8 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
WebSocketDialogMsgTodo::whereIn('msg_id', $ids)->delete();
|
||||
self::whereIn('id', $ids)->delete();
|
||||
//
|
||||
$dialogDatas = WebSocketDialog::whereIn('id', $dialogIds)->get();
|
||||
foreach ($dialogDatas as $dialogData) {
|
||||
$dialogData->updateMsgLastAt();
|
||||
foreach ($dialogIds as $dialogId) {
|
||||
WebSocketDialogUser::updateMsgLastAt($dialogId);
|
||||
}
|
||||
foreach ($replyIds as $id) {
|
||||
self::whereId($id)->update(['reply_num' => self::whereReplyId($id)->count()]);
|
||||
@@ -501,7 +500,7 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
'data' => [
|
||||
'id' => $this->id,
|
||||
'dialog_id' => $this->dialog_id,
|
||||
'last_msg' => $dialogData->updateMsgLastAt(),
|
||||
'last_msg' => WebSocketDialogUser::updateMsgLastAt($this->dialog_id),
|
||||
'update_read' => $deleteRead ? 1 : 0
|
||||
],
|
||||
]
|
||||
@@ -786,7 +785,20 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
}
|
||||
// 过滤标签
|
||||
$text = strip_tags($text, '<blockquote> <strong> <pre> <ol> <ul> <li> <em> <p> <s> <u> <a>');
|
||||
$text = preg_replace("/\<(blockquote|strong|pre|ol|ul|li|em|p|s|u).*?\>/is", "<$1>", $text); // 不用去除a标签,上面已经处理过了
|
||||
$text = preg_replace_callback("/\<(blockquote|strong|pre|ol|ul|li|em|p|s|u)(.*?)\>/is", function (array $match) { // 不用去除a标签,上面已经处理过了
|
||||
preg_match("/<[^>]*?style=([\"'])(.*?)\\1[^>]*?>/is", $match[0], $matchs);
|
||||
$attach = '';
|
||||
if ($matchs) {
|
||||
$styleArray = explode(';', $matchs[2]);
|
||||
$validStyles = array_filter($styleArray, function ($styleItem) {
|
||||
return preg_match('/\s*(?:color|font-size|background-color|font-weight|font-family|text-decoration|font-style)\s*:/i', $styleItem); // 只保留指定样式
|
||||
});
|
||||
if ($validStyles) {
|
||||
$attach = ' style="' . implode(';', $validStyles) . '"';
|
||||
}
|
||||
}
|
||||
return "<{$match[1]}{$attach}>";
|
||||
}, $text);
|
||||
$text = preg_replace_callback("/\[:LINK:(.*?):(.*?):\]/i", function (array $match) {
|
||||
return "<a href=\"" . base64_decode($match[1]) . "\" target=\"_blank\">" . base64_decode($match[2]) . "</a>";
|
||||
}, $text);
|
||||
@@ -846,10 +858,10 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
$push_silence = !in_array($type, ["text", "file", "record", "meeting"]);
|
||||
}
|
||||
//
|
||||
$update_id = preg_match("/^update-(\d+)$/", $action, $match) ? $match[1] : 0;
|
||||
$change_id = preg_match("/^change-(\d+)$/", $action, $match) ? $match[1] : 0;
|
||||
$reply_id = preg_match("/^reply-(\d+)$/", $action, $match) ? $match[1] : 0;
|
||||
$forward_id = preg_match("/^forward-(\d+)-(\d+)$/", $action, $match) ? $match[2] : 0;
|
||||
$update_id = intval(preg_match("/^update-(\d+)$/", $action, $match) ? $match[1] : 0);
|
||||
$change_id = intval(preg_match("/^change-(\d+)$/", $action, $match) ? $match[1] : 0);
|
||||
$reply_id = intval(preg_match("/^reply-(\d+)$/", $action, $match) ? $match[1] : 0);
|
||||
$forward_id = intval(preg_match("/^forward-(\d+)$/", $action, $match) ? $match[1] : 0);
|
||||
$sender = $sender === null ? User::userid() : $sender;
|
||||
//
|
||||
$dialog = WebSocketDialog::find($dialog_id);
|
||||
@@ -871,23 +883,37 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
if (empty($dialogMsg)) {
|
||||
throw new ApiException('消息不存在');
|
||||
}
|
||||
if ($dialogMsg->type !== 'text' && $dialogMsg->type !== 'vote') {
|
||||
throw new ApiException('此消息不支持此操作');
|
||||
}
|
||||
if ($dialogMsg->userid != $sender && $dialogMsg->type !== 'vote') {
|
||||
throw new ApiException('仅支持修改自己的消息');
|
||||
$oldMsg = Base::json2array($dialogMsg->getRawOriginal('msg'));
|
||||
if ($dialogMsg->type === 'vote') {
|
||||
if ($dialogMsg->userid != $sender) {
|
||||
$msg = [
|
||||
'votes' => $msg['votes'],
|
||||
];
|
||||
}
|
||||
} else {
|
||||
if ($dialogMsg->type !== 'text') {
|
||||
throw new ApiException('此消息不支持此操作');
|
||||
}
|
||||
if ($dialogMsg->userid != $sender) {
|
||||
throw new ApiException('仅支持修改自己的消息');
|
||||
}
|
||||
}
|
||||
//
|
||||
$updateData = [
|
||||
'mtype' => $mtype,
|
||||
'link' => $link,
|
||||
'msg' => $msg,
|
||||
'msg' => array_merge($oldMsg, $msg),
|
||||
'modify' => $modify,
|
||||
];
|
||||
$dialogMsg->updateInstance($updateData);
|
||||
$dialogMsg->key = $dialogMsg->generateMsgKey();
|
||||
$dialogMsg->save();
|
||||
//
|
||||
WebSocketDialogUser::whereDialogId($dialog->id)->whereUserid($sender)->whereHide(1)->change([
|
||||
'hide' => 0, // 修改消息时,显示会话(仅自己)
|
||||
'updated_at' => Carbon::now()->toDateTimeString('millisecond'),
|
||||
]);
|
||||
//
|
||||
$dialogMsg->msgJoinGroup($dialog);
|
||||
//
|
||||
$dialog->pushMsg('update', array_merge($updateData, [
|
||||
@@ -897,34 +923,53 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
return Base::retSuccess('修改成功', $dialogMsg);
|
||||
} else {
|
||||
// 发送
|
||||
if ($reply_id && !self::whereId($reply_id)->increment('reply_num')) {
|
||||
throw new ApiException('回复的消息不存在');
|
||||
}
|
||||
// 转发
|
||||
if ($forward_id && !self::whereId($forward_id)->increment('forward_num')) {
|
||||
throw new ApiException('转发的消息不存在');
|
||||
if ($reply_id) {
|
||||
// 回复
|
||||
$replyRow = self::whereId($reply_id)->whereDialogId($dialog_id)->first();
|
||||
if (empty($replyRow)) {
|
||||
throw new ApiException('回复的消息不存在');
|
||||
}
|
||||
$replyMsg = Base::json2array($replyRow->getRawOriginal('msg'));
|
||||
unset($replyMsg['reply_data']);
|
||||
$msg['reply_data'] = [
|
||||
'id' => $replyRow->id,
|
||||
'userid' => $replyRow->userid,
|
||||
'type' => $replyRow->type,
|
||||
'msg' => $replyMsg,
|
||||
];
|
||||
$replyRow->increment('reply_num');
|
||||
}
|
||||
//
|
||||
$dialogMsg = self::createInstance([
|
||||
'dialog_id' => $dialog_id,
|
||||
'dialog_type' => $dialog->type,
|
||||
'reply_id' => $reply_id,
|
||||
'forward_id' => $forward_id,
|
||||
'userid' => $sender,
|
||||
'type' => $type,
|
||||
'mtype' => $mtype,
|
||||
'link' => $link,
|
||||
'msg' => $msg,
|
||||
'read' => 0,
|
||||
'forward_id' => $forward_id,
|
||||
'forward_show' => $forward_id ? $match[1] : 1,
|
||||
]);
|
||||
AbstractModel::transaction(function () use ($dialog, $dialogMsg) {
|
||||
$dialog->last_at = Carbon::now();
|
||||
$dialog->save();
|
||||
AbstractModel::transaction(function () use ($dialogMsg) {
|
||||
$dialogMsg->send = 1;
|
||||
$dialogMsg->key = $dialogMsg->generateMsgKey();
|
||||
$dialogMsg->save();
|
||||
WebSocketDialogUser::whereDialogId($dialog->id)->change(['updated_at' => Carbon::now()->toDateTimeString('millisecond')]);
|
||||
//
|
||||
if ($dialogMsg->type === 'meeting') {
|
||||
MeetingMsg::createInstance([
|
||||
'meetingid' => $dialogMsg->msg['meetingid'],
|
||||
'dialog_id' => $dialogMsg->dialog_id,
|
||||
'msg_id' => $dialogMsg->id,
|
||||
])->save();
|
||||
}
|
||||
//
|
||||
WebSocketDialogUser::whereDialogId($dialogMsg->dialog_id)->change([
|
||||
'hide' => 0, // 有新消息时,显示会话(会话内所有会员)
|
||||
'last_at' => Carbon::now(),
|
||||
'updated_at' => Carbon::now()->toDateTimeString('millisecond'),
|
||||
]);
|
||||
});
|
||||
//
|
||||
$task = new WebSocketDialogMsgTask($dialogMsg->id);
|
||||
|
||||
@@ -17,9 +17,15 @@ use Carbon\Carbon;
|
||||
* @property int|null $after 在阅读之后才添加的记录
|
||||
* @property string|null $read_at 阅读时间
|
||||
* @property-read \App\Models\WebSocketDialogMsg|null $webSocketDialogMsg
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead whereAfter($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead whereDialogId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead whereEmail($value)
|
||||
|
||||
@@ -11,9 +11,15 @@ namespace App\Models;
|
||||
* @property int|null $userid 接收会员ID
|
||||
* @property string|null $done_at 完成时间
|
||||
* @property-read array|mixed $msg_data
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgTodo newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgTodo newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgTodo query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgTodo whereDialogId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgTodo whereDoneAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgTodo whereId($value)
|
||||
|
||||
@@ -11,23 +11,33 @@ use Carbon\Carbon;
|
||||
* @property int|null $dialog_id 对话ID
|
||||
* @property int|null $userid 会员ID
|
||||
* @property string|null $top_at 置顶时间
|
||||
* @property string|null $last_at 最后消息时间
|
||||
* @property int|null $mark_unread 是否标记为未读:0否,1是
|
||||
* @property int|null $silence 是否免打扰:0否,1是
|
||||
* @property int|null $hide 不显示会话:0否,1是
|
||||
* @property int|null $inviter 邀请人
|
||||
* @property int|null $important 是否不可移出(项目、任务人员)
|
||||
* @property int|null $important 是否不可移出(项目、任务、部门人员)
|
||||
* @property string|null $color 颜色
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\WebSocketDialog|null $webSocketDialog
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereColor($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereDialogId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereHide($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereImportant($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereInviter($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereLastAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereMarkUnread($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereSilence($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereTopAt($value)
|
||||
@@ -46,4 +56,17 @@ class WebSocketDialogUser extends AbstractModel
|
||||
{
|
||||
return $this->hasOne(WebSocketDialog::class, 'id', 'dialog_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新对话最后消息时间
|
||||
* @return WebSocketDialogMsg|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|\Illuminate\Database\Query\Builder|object|null
|
||||
*/
|
||||
public static function updateMsgLastAt($dialogId)
|
||||
{
|
||||
$lastMsg = WebSocketDialogMsg::whereDialogId($dialogId)->orderByDesc('id')->first();
|
||||
if ($lastMsg) {
|
||||
WebSocketDialogUser::whereDialogId($dialogId)->change(['last_at' => $lastMsg->created_at]);
|
||||
}
|
||||
return $lastMsg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,15 @@ namespace App\Models;
|
||||
* @property int|null $create_id 所属会员ID
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel change($array)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketTmpMsg newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketTmpMsg newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketTmpMsg query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel remove()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketTmpMsg whereCreateId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketTmpMsg whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketTmpMsg whereId($value)
|
||||
|
||||
@@ -133,7 +133,8 @@ class Base
|
||||
|
||||
/**
|
||||
* 判断客户端版本
|
||||
* @param $min
|
||||
* @param $min // 最小版本(满足此版本返回true)
|
||||
* @param null $clientVersion
|
||||
* @return bool
|
||||
*/
|
||||
public static function judgeClientVersion($min, $clientVersion = null)
|
||||
@@ -2472,13 +2473,18 @@ class Base
|
||||
*/
|
||||
public static function extIcon($ext)
|
||||
{
|
||||
return match ($ext) {
|
||||
"docx" => 'images/ext/doc.png',
|
||||
"xlsx" => 'images/ext/xls.png',
|
||||
"pptx" => 'images/ext/ppt.png',
|
||||
"ai", "avi", "bmp", "cdr", "doc", "eps", "gif", "mov", "mp3", "mp4", "pdf", "ppt", "pr", "psd", "rar", "svg", "tif", "txt", "xls", "zip" => 'images/ext/' . $ext . '.png',
|
||||
default => 'images/ext/file.png',
|
||||
};
|
||||
if ($ext == "docx") {
|
||||
$ext = 'doc';
|
||||
} elseif ($ext == "xlsx") {
|
||||
$ext = 'xls';
|
||||
} elseif ($ext == "pptx") {
|
||||
$ext = 'ppt';
|
||||
}
|
||||
if (in_array($ext, ["ai", "avi", "bmp", "cdr", "doc", "eps", "gif", "mov", "mp3", "mp4", "pdf", "ppt", "pr", "psd", "rar", "svg", "tif", "txt", "xls", "zip"])) {
|
||||
return 'images/ext/' . $ext . '.png';
|
||||
} else {
|
||||
return 'images/ext/file.png';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -228,6 +228,14 @@ class Doo
|
||||
if (Base::isError($data)) {
|
||||
throw new ApiException($data['msg'] ?: '注册失败');
|
||||
}
|
||||
if (\DB::transactionLevel() > 0) {
|
||||
try {
|
||||
\DB::commit();
|
||||
\DB::beginTransaction();
|
||||
} catch (\Throwable) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
$user = User::whereEmail($email)->first();
|
||||
if (empty($user)) {
|
||||
throw new ApiException('注册失败');
|
||||
|
||||
@@ -174,19 +174,16 @@ class Extranet
|
||||
|
||||
/**
|
||||
* 随机笑话接口
|
||||
* @return array
|
||||
* @return string
|
||||
*/
|
||||
public static function randJoke(): array
|
||||
public static function randJoke(): string
|
||||
{
|
||||
$jokeKey = env("JUKE_KEY_JOKE");
|
||||
if ($jokeKey) {
|
||||
$data = self::curl("http://v.juhe.cn/joke/randJoke.php?key=" . $jokeKey);
|
||||
$data = Base::json2array($data);
|
||||
if ($data['reason'] === 'success') {
|
||||
return $data['result'];
|
||||
}
|
||||
$data = self::curl("https://hmajax.itheima.net/api/randjoke");
|
||||
$data = Base::json2array($data);
|
||||
if ($data['message'] === '获取成功' && $text = trim($data['data'])) {
|
||||
return $text;
|
||||
}
|
||||
return [];
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,13 +192,10 @@ class Extranet
|
||||
*/
|
||||
public static function soups(): string
|
||||
{
|
||||
$soupKey = env("JUKE_KEY_SOUP");
|
||||
if ($soupKey) {
|
||||
$data = self::curl("https://apis.juhe.cn/fapig/soup/query?key=" . $soupKey);
|
||||
$data = Base::json2array($data);
|
||||
if ($data['reason'] === 'success' && $text = trim($data['result']['text'])) {
|
||||
return $text;
|
||||
}
|
||||
$data = self::curl("https://hmajax.itheima.net/api/ambition");
|
||||
$data = Base::json2array($data);
|
||||
if ($data['message'] === '获取成功' && $text = trim($data['data'])) {
|
||||
return $text;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class TimeRange
|
||||
public function __construct($data)
|
||||
{
|
||||
if (is_array($data)) {
|
||||
$range = explode("-", str_replace([",", "|"], "-", $data['timerange']));
|
||||
$range = $this->format($data['timerange']);
|
||||
if ($data['updated_at'] || $data['at_after']) {
|
||||
$range[0] = $data['updated_at'] ?: $data['at_after'];
|
||||
}
|
||||
@@ -23,14 +23,27 @@ class TimeRange
|
||||
$range[1] = $data['deleted_at'];
|
||||
}
|
||||
} else {
|
||||
$range = explode("-", str_replace([",", "|"], "-", $data));
|
||||
$range = $this->format($data);
|
||||
}
|
||||
//
|
||||
$updated = Base::isNumber($range[0]) ? intval($range[0]) : trim($range[0]);
|
||||
$deleted = Base::isNumber($range[1]) ? intval($range[1]) : trim($range[1]);
|
||||
//
|
||||
$this->updated = $updated ? Carbon::parse($updated) : null;
|
||||
$this->deleted = $deleted ? Carbon::parse($deleted) : null;
|
||||
$timezone = config('app.timezone');
|
||||
$this->updated = $updated ? Carbon::parse($updated)->setTimezone($timezone) : null;
|
||||
$this->deleted = $deleted ? Carbon::parse($deleted)->setTimezone($timezone) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $timerange
|
||||
* - 格式1:2021-01-01 00:00:00,2021-01-01 23:59:59
|
||||
* - 格式2:1612051200-1612137599
|
||||
* @return array
|
||||
*/
|
||||
private function format($timerange)
|
||||
{
|
||||
$search = str_contains($timerange, ":") ? ["|"] : ["|", "-"];
|
||||
return explode(",", str_replace($search, ",", $timerange));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Observers;
|
||||
|
||||
use App\Models\Deleted;
|
||||
use App\Models\WebSocketDialogUser;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class WebSocketDialogUserObserver
|
||||
{
|
||||
@@ -15,6 +16,18 @@ class WebSocketDialogUserObserver
|
||||
*/
|
||||
public function created(WebSocketDialogUser $webSocketDialogUser)
|
||||
{
|
||||
if (!$webSocketDialogUser->last_at) {
|
||||
if (in_array($webSocketDialogUser->webSocketDialog?->group_type, ['user', 'department', 'all'])) {
|
||||
$webSocketDialogUser->last_at = Carbon::now();
|
||||
$webSocketDialogUser->save();
|
||||
} else {
|
||||
$item = WebSocketDialogUser::whereDialogId($webSocketDialogUser->dialog_id)->orderByDesc('last_at')->first();
|
||||
if ($item?->last_at) {
|
||||
$webSocketDialogUser->last_at = $item->last_at;
|
||||
$webSocketDialogUser->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
Deleted::forget('dialog', $webSocketDialogUser->dialog_id, $webSocketDialogUser->userid);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ class WebSocketService implements WebSocketHandlerInterface
|
||||
'type' => 'open',
|
||||
'data' => [
|
||||
'fd' => $fd,
|
||||
'ud' => $user->userid,
|
||||
],
|
||||
]));
|
||||
// 通知上线
|
||||
|
||||
@@ -316,12 +316,12 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
$nameKey = $isManager ? $array[2] : $array[1];
|
||||
$data = $this->botManagerOne($botId, $msg->userid);
|
||||
if ($data) {
|
||||
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread', 'u.silence', 'u.color', 'u.updated_at as user_at'])
|
||||
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->where('web_socket_dialogs.name', 'LIKE', "%{$nameKey}%")
|
||||
->where('u.userid', $data->userid)
|
||||
->orderByDesc('u.top_at')
|
||||
->orderByDesc('web_socket_dialogs.last_at')
|
||||
->orderByDesc('u.last_at')
|
||||
->take(20)
|
||||
->get();
|
||||
if ($list->isEmpty()) {
|
||||
@@ -380,6 +380,7 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
'openai_agency' => $setting['openai_agency'],
|
||||
'openai_model' => $setting['openai_model'],
|
||||
'server_url' => $serverUrl,
|
||||
'chunk_size' => 7,
|
||||
];
|
||||
if (empty($extras['openai_key'])) {
|
||||
$error = 'Robot disabled.';
|
||||
@@ -437,6 +438,24 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
$error = 'The client version is low (required version ≥ v0.29.12).';
|
||||
}
|
||||
break;
|
||||
// Gemini 机器人
|
||||
case 'ai-gemini@bot.system':
|
||||
$setting = Base::setting('aibotSetting');
|
||||
$webhookUrl = "{$serverUrl}/ai/gemini/send";
|
||||
$extras = [
|
||||
'gemini_key' => $setting['gemini_key'],
|
||||
'gemini_model' => $setting['gemini_model'],
|
||||
'gemini_agency' => $setting['gemini_agency'],
|
||||
'gemini_timeout' => 20,
|
||||
'server_url' => $serverUrl,
|
||||
];
|
||||
if (empty($extras['gemini_key'])) {
|
||||
$error = 'Robot disabled.';
|
||||
} elseif (in_array($this->client['platform'], ['win', 'mac', 'web'])
|
||||
&& !Base::judgeClientVersion("0.29.11", $this->client['version'])) {
|
||||
$error = 'The client version is low (required version ≥ v0.29.12).';
|
||||
}
|
||||
break;
|
||||
// 其他机器人
|
||||
default:
|
||||
$userBot = UserBot::whereBotId($botUser->userid)->first();
|
||||
@@ -452,7 +471,7 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
}
|
||||
//
|
||||
try {
|
||||
$res = Ihttp::ihttp_post($webhookUrl, [
|
||||
$data = [
|
||||
'text' => $command,
|
||||
'token' => User::generateToken($botUser),
|
||||
'dialog_id' => $dialog->id,
|
||||
@@ -463,7 +482,8 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
'bot_uid' => $botUser->userid,
|
||||
'version' => Base::getVersion(),
|
||||
'extras' => Base::array2json($extras)
|
||||
], 10);
|
||||
];
|
||||
$res = Ihttp::ihttp_post($webhookUrl, $data);
|
||||
if ($userBot) {
|
||||
$userBot->webhook_num++;
|
||||
$userBot->save();
|
||||
|
||||
132
app/Tasks/CloseMeetingRoomTask.php
Normal file
132
app/Tasks/CloseMeetingRoomTask.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tasks;
|
||||
|
||||
use App\Models\Meeting;
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Module\Base;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
|
||||
|
||||
class CloseMeetingRoomTask extends AbstractTask
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
// 10分钟执行一次
|
||||
$time = intval(Cache::get("CloseMeetingRoomTask:Time"));
|
||||
if (time() - $time < 600) {
|
||||
return;
|
||||
}
|
||||
Cache::put("CloseMeetingRoomTask:Time", time(), Carbon::now()->addMinutes(10));
|
||||
// 判断参数
|
||||
$setting = Base::setting('meetingSetting');
|
||||
if ($setting['open'] !== 'open') {
|
||||
return;
|
||||
}
|
||||
if (empty($setting['appid']) ||empty($setting['api_key']) || empty($setting['api_secret'])) {
|
||||
return;
|
||||
}
|
||||
$credentials = $setting['api_key'] . ":" . $setting['api_secret'];
|
||||
$base64Credentials = base64_encode($credentials);
|
||||
$arrHeader = [
|
||||
"Accept: application/json",
|
||||
"Authorization: Basic " . $base64Credentials
|
||||
];
|
||||
// 获取10分钟未更新的会议
|
||||
$meetings = Meeting::whereNull('end_at')
|
||||
->where('updated_at', '<', Carbon::now()->subMinutes(10))
|
||||
->take(100)
|
||||
->get();
|
||||
$dialogIds = [];
|
||||
/** @var Meeting $meeting */
|
||||
foreach ($meetings as $meeting) {
|
||||
if (!$this->isEmptyChannel($setting['appid'], $meeting->channel, $arrHeader)) {
|
||||
$meeting->updated_at = Carbon::now();
|
||||
$meeting->save();
|
||||
continue;
|
||||
}
|
||||
$meeting->end_at = Carbon::now();
|
||||
$meeting->save();
|
||||
// 更新消息
|
||||
$newMsg = $meeting->toArray();
|
||||
$newMsg['end_at'] = $meeting->end_at->toDateTimeString();
|
||||
WebSocketDialogMsg::select(['web_socket_dialog_msgs.*', 'm.meetingid'])
|
||||
->join("meeting_msgs as m", "m.msg_id", "=", "web_socket_dialog_msgs.id")
|
||||
->where('m.meetingid', $meeting->meetingid)
|
||||
->chunk(100, function ($msgs) use ($newMsg, &$dialogIds) {
|
||||
/** @var WebSocketDialogMsg $msg */
|
||||
foreach ($msgs as $msg) {
|
||||
$msgData = Base::json2array($msg->getRawOriginal('msg'));
|
||||
$msg->msg = Base::array2json(array_merge($msgData, $newMsg));
|
||||
$msg->save();
|
||||
//
|
||||
if (!isset($dialogIds[$msg->dialog_id])) {
|
||||
$dialogIds[$msg->dialog_id] = [];
|
||||
}
|
||||
$dialogIds[$msg->dialog_id][] = [
|
||||
'id' => $msg->id,
|
||||
'msg' => $msg->msg,
|
||||
];
|
||||
}
|
||||
});
|
||||
}
|
||||
// 推送更新
|
||||
foreach ($dialogIds as $dialogId => $datas) {
|
||||
$dialog = WebSocketDialog::find($dialogId);
|
||||
if (empty($dialog)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($datas as $data) {
|
||||
$dialog->pushMsg('update', $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function end()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否空频道
|
||||
* @param $appid
|
||||
* @param $channel
|
||||
* @param $arrHeader
|
||||
* @return bool
|
||||
*/
|
||||
private function isEmptyChannel($appid, $channel, $arrHeader)
|
||||
{
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, [
|
||||
CURLOPT_URL => "https://api.sd-rtn.com/dev/v1/channel/user/{$appid}/{$channel}",
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_ENCODING => "",
|
||||
CURLOPT_MAXREDIRS => 10,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_CUSTOMREQUEST => "GET",
|
||||
CURLOPT_HTTPHEADER => $arrHeader,
|
||||
]);
|
||||
$response = curl_exec($curl);
|
||||
$err = curl_error($curl);
|
||||
curl_close($curl);
|
||||
if ($err) {
|
||||
return false; // 错误
|
||||
}
|
||||
$data = Base::json2array($response);
|
||||
if (!$data['success']) {
|
||||
return false; // 失败
|
||||
}
|
||||
if ($data['data']['channel_exist']) {
|
||||
return false; // 有人
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -13,13 +13,15 @@ use Carbon\Carbon;
|
||||
/**
|
||||
* 获取笑话、心灵鸡汤
|
||||
*
|
||||
* 在.env添加笑话 JUKE_KEY_JOKE
|
||||
* 在.env添加鸡汤 JUKE_KEY_SOUP
|
||||
*
|
||||
* 每日小时采集1次
|
||||
* 每分钟采集1次
|
||||
*/
|
||||
class JokeSoupTask extends AbstractTask
|
||||
{
|
||||
public static function keyName($key)
|
||||
{
|
||||
return "JokeSoupTask-v2:{$key}";
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
@@ -27,27 +29,25 @@ class JokeSoupTask extends AbstractTask
|
||||
|
||||
public function start()
|
||||
{
|
||||
// 判断每小时执行一次
|
||||
if (Cache::get("JokeSoupTask:YmdH") == date("YmdH")) {
|
||||
// 判断每分钟执行一次
|
||||
if (Cache::get(self::keyName("YmdHi")) == date("YmdHi")) {
|
||||
return;
|
||||
}
|
||||
Cache::put("JokeSoupTask:YmdH", date("YmdH"), Carbon::now()->addDay());
|
||||
Cache::put(self::keyName("YmdHi"), date("YmdHi"), Carbon::now()->addDay());
|
||||
//
|
||||
$array = Base::json2array(Cache::get("JokeSoupTask:jokes"));
|
||||
$array = Base::json2array(Cache::get(self::keyName("jokes")));
|
||||
$data = Extranet::randJoke();
|
||||
foreach ($data as $item) {
|
||||
if ($text = trim($item['content'])) {
|
||||
$array[] = $text;
|
||||
}
|
||||
if ($data) {
|
||||
$array[] = $data;
|
||||
}
|
||||
Cache::forever("JokeSoupTask:jokes", Base::array2json(array_slice($array, -100)));
|
||||
Cache::forever(self::keyName("jokes"), Base::array2json(array_slice($array, -200)));
|
||||
//
|
||||
$array = Base::json2array(Cache::get("JokeSoupTask:soups"));
|
||||
$array = Base::json2array(Cache::get(self::keyName("soups")));
|
||||
$data = Extranet::soups();
|
||||
if ($data) {
|
||||
$array[] = $data;
|
||||
}
|
||||
Cache::forever("JokeSoupTask:soups", Base::array2json(array_slice($array, -24)));
|
||||
Cache::forever(self::keyName("soups"), Base::array2json(array_slice($array, -200)));
|
||||
}
|
||||
|
||||
public function end()
|
||||
|
||||
@@ -41,7 +41,7 @@ class WebSocketDialogMsgTask extends AbstractTask
|
||||
// 判断是否有Request方法,兼容go协程请求
|
||||
$this->ignoreFd = $ignoreFd;
|
||||
$this->client = [];
|
||||
if (method_exists(new Request,"header")) {
|
||||
if (method_exists(request(), "header")) {
|
||||
$this->ignoreFd = $ignoreFd === null ? Request::header('fd') : $ignoreFd;
|
||||
$this->client = [
|
||||
'version' => Base::headerOrInput('version'),
|
||||
|
||||
169
bin/https
Normal file
169
bin/https
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/bin/sh
|
||||
|
||||
#fonts color
|
||||
Green="\033[32m"
|
||||
Yellow="\033[33m"
|
||||
Red="\033[31m"
|
||||
GreenBG="\033[42;37m"
|
||||
YellowBG="\033[43;37m"
|
||||
RedBG="\033[41;37m"
|
||||
Font="\033[0m"
|
||||
|
||||
#notification information
|
||||
OK="${Green}[OK]${Font}"
|
||||
Warn="${Yellow}[警告]${Font}"
|
||||
Error="${Red}[错误]${Font}"
|
||||
|
||||
cd "$(
|
||||
cd "$(dirname "$0")" || exit
|
||||
pwd
|
||||
)" || exit
|
||||
|
||||
#================================================================
|
||||
#================================================================
|
||||
|
||||
success() {
|
||||
echo -e "${OK} ${GreenBG}$1${Font}"
|
||||
}
|
||||
|
||||
warning() {
|
||||
echo -e "${Warn} ${YellowBG}$1${Font}"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${Error} ${RedBG}$1${Font}"
|
||||
}
|
||||
|
||||
info() {
|
||||
echo -e "$1"
|
||||
}
|
||||
|
||||
env_get() {
|
||||
local key=$1
|
||||
local value=`cat $(dirname "$PWD")/.env | grep "^$key=" | awk -F '=' '{print $2}'`
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
env_set() {
|
||||
local key=$1
|
||||
local val=$2
|
||||
local exist=`cat $(dirname "$PWD")/.env | grep "^$key="`
|
||||
if [ -z "$exist" ]; then
|
||||
echo "$key=$val" >> $(dirname "$PWD")/.env
|
||||
else
|
||||
sed -i "/^${key}=/c\\${key}=${val}" $(dirname "$PWD")/.env
|
||||
fi
|
||||
}
|
||||
|
||||
#================================================================
|
||||
#================================================================
|
||||
|
||||
check() {
|
||||
while [ -z "$domain" ]; do
|
||||
read -rp "请输入你的域名: " domain
|
||||
# 判断域名是否合法
|
||||
if [ -z "$domain" ]; then
|
||||
error "域名不能为空"
|
||||
elif [ -z "$(echo "$domain" | grep -E '^[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+$')" ]; then
|
||||
error "域名格式不正确"
|
||||
domain=""
|
||||
fi
|
||||
done
|
||||
|
||||
success "正在域名DNS解析IP..."
|
||||
local domain_ip=$(ping -c 1 "${domain}" 2>/dev/null | grep PING | cut -d "(" -f2 | cut -d ")" -f1)
|
||||
local local_ip=$(curl -sk ip.sb)
|
||||
info "域名DNS解析IP: ${domain_ip}"
|
||||
info "本机IP: ${local_ip}"
|
||||
|
||||
sleep 2
|
||||
if [[ "$(echo "${local_ip}" | tr '.' '+' | bc)" == "$(echo "${domain_ip}" | tr '.' '+' | bc)" ]]; then
|
||||
success "域名DNS解析IP 与 本机IP 匹配"
|
||||
sleep 2
|
||||
else
|
||||
warning "域名DNS解析IP 与 本机IP 不匹配,是否继续操作? [Y/n]"
|
||||
read -r continue_next
|
||||
[[ -z ${continue_next} ]] && continue_next="Y"
|
||||
case $continue_next in
|
||||
[yY][eE][sS] | [yY])
|
||||
success "继续操作"
|
||||
sleep 2
|
||||
;;
|
||||
*)
|
||||
error "操作终止"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
install() {
|
||||
local sitePath="$(dirname "$PWD")/docker/nginx/site"
|
||||
local sslPath="$sitePath/ssl"
|
||||
if [[ -f "$sslPath/$domain.key" && -f "$sslPath/$domain.crt" ]]; then
|
||||
warning "$domain 证书文件已存在,是否删除并继续操作? [Y/n]"
|
||||
read -r continue_install
|
||||
[[ -z ${continue_install} ]] && continue_install="Y"
|
||||
case $continue_install in
|
||||
[yY][eE][sS] | [yY])
|
||||
rm -f "$sslPath/$domain.key"
|
||||
rm -f "$sslPath/$domain.crt"
|
||||
success "继续操作"
|
||||
sleep 2
|
||||
;;
|
||||
*)
|
||||
error "操作终止"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
apk add --no-cache openssl socat
|
||||
curl https://get.acme.sh | sh
|
||||
if [[ 0 -ne $? ]]; then
|
||||
error "安装证书生成脚本失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if /root/.acme.sh/acme.sh --issue -d "${domain}" -w "$(dirname "$PWD")/public" --standalone -k ec-256 --force --test; then
|
||||
success "SSL 证书测试签发成功,开始正式签发"
|
||||
rm -rf "/root/.acme.sh/${domain}_ecc"
|
||||
sleep 2
|
||||
else
|
||||
error "SSL 证书测试签发失败"
|
||||
rm -rf "root/.acme.sh/${domain}_ecc"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if /root/.acme.sh/acme.sh --issue -d "${domain}" -w "$(dirname "$PWD")/public" --server letsencrypt --standalone -k ec-256 --force; then
|
||||
success "SSL 证书生成成功"
|
||||
sleep 2
|
||||
mkdir -p $sslPath
|
||||
if /root/.acme.sh/acme.sh --installcert -d "${domain}" --fullchainpath "${sslPath}/${domain}.crt" --keypath "${sslPath}/${domain}.key" --ecc --force; then
|
||||
success "SSL 证书配置成功"
|
||||
sleep 2
|
||||
fi
|
||||
else
|
||||
error "SSL 证书生成失败"
|
||||
rm -rf "/root/.acme.sh/${domain}_ecc"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
env_set "APP_URL" "https://${domain}"
|
||||
|
||||
cat >${sitePath}/ssl.conf <<EOF
|
||||
server_name ${domain};
|
||||
listen 443 ssl;
|
||||
ssl_certificate /etc/nginx/conf.d/site/ssl/${domain}.crt;
|
||||
ssl_certificate_key /etc/nginx/conf.d/site/ssl/${domain}.key;
|
||||
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
error_page 497 https://\$host\$request_uri;
|
||||
EOF
|
||||
}
|
||||
|
||||
check
|
||||
install
|
||||
25
version.js → bin/version.js
vendored
25
version.js → bin/version.js
vendored
@@ -17,12 +17,33 @@ function runExec(command, cb) {
|
||||
});
|
||||
}
|
||||
|
||||
function removeDuplicateLines(log) {
|
||||
const logs = log.split(/(\n## \[.*?\])/)
|
||||
if (logs) {
|
||||
log = logs.map(str => {
|
||||
const array = [];
|
||||
const items = str.split("\n");
|
||||
items.some(item => {
|
||||
if (/^-/.test(item)) {
|
||||
if (array.indexOf(item) === -1) {
|
||||
array.push(item);
|
||||
}
|
||||
} else {
|
||||
array.push(item);
|
||||
}
|
||||
})
|
||||
return array.join("\n");
|
||||
}).join('');
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
runExec("git rev-list --count HEAD $(git branch | sed -n -e 's/^\* \(.*\)/\1/p')", function (err, response) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
const num = 1238 + parseInt(response)
|
||||
const num = 1250 + parseInt(response)
|
||||
if (isNaN(num) || Math.floor(num % 100) < 0) {
|
||||
console.error("get version error " + response);
|
||||
return;
|
||||
@@ -43,7 +64,7 @@ runExec("git rev-list --count HEAD $(git branch | sed -n -e 's/^\* \(.*\)/\1/p')
|
||||
console.error("Change file does not exist");
|
||||
return "";
|
||||
}
|
||||
let newContent = fs.readFileSync(changeFile, 'utf8');
|
||||
let newContent = removeDuplicateLines(fs.readFileSync(changeFile, 'utf8'));
|
||||
if (newContent.indexOf("## [Unreleased]") !== -1) {
|
||||
newContent = newContent.replace("## [Unreleased]", `## [${ver}]`);
|
||||
} else {
|
||||
148
cmd
148
cmd
@@ -2,13 +2,16 @@
|
||||
|
||||
#fonts color
|
||||
Green="\033[32m"
|
||||
Yellow="\033[33m"
|
||||
Red="\033[31m"
|
||||
GreenBG="\033[42;37m"
|
||||
YellowBG="\033[43;37m"
|
||||
RedBG="\033[41;37m"
|
||||
Font="\033[0m"
|
||||
|
||||
#notification information
|
||||
OK="${Green}[OK]${Font}"
|
||||
Warn="${Yellow}[警告]${Font}"
|
||||
Error="${Red}[错误]${Font}"
|
||||
|
||||
cur_path="$(pwd)"
|
||||
@@ -17,14 +20,30 @@ COMPOSE="docker-compose"
|
||||
|
||||
judge() {
|
||||
if [[ 0 -eq $? ]]; then
|
||||
echo -e "${OK} ${GreenBG} $1 完成 ${Font}"
|
||||
success "$1 完成"
|
||||
sleep 1
|
||||
else
|
||||
echo -e "${Error} ${RedBG} $1 失败${Font}"
|
||||
error "$1 失败"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "${OK} ${GreenBG}$1${Font}"
|
||||
}
|
||||
|
||||
warning() {
|
||||
echo -e "${Warn} ${YellowBG}$1${Font}"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${Error} ${RedBG}$1${Font}"
|
||||
}
|
||||
|
||||
info() {
|
||||
echo -e "$1"
|
||||
}
|
||||
|
||||
rand() {
|
||||
local min=$1
|
||||
local max=$(($2-$min+1))
|
||||
@@ -51,7 +70,7 @@ restart_php() {
|
||||
$COMPOSE stop php
|
||||
$COMPOSE start php
|
||||
else
|
||||
echo -e "$RES"
|
||||
info "$RES"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -69,21 +88,21 @@ switch_debug() {
|
||||
check_docker() {
|
||||
docker --version &> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${Error} ${RedBG} 未安装 Docker!${Font}"
|
||||
error "未安装 Docker!"
|
||||
exit 1
|
||||
fi
|
||||
docker-compose version &> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
docker compose version &> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${Error} ${RedBG} 未安装 Docker-compose!${Font}"
|
||||
error "未安装 Docker-compose!"
|
||||
exit 1
|
||||
fi
|
||||
COMPOSE="docker compose"
|
||||
fi
|
||||
if [[ -n `$COMPOSE version | grep -E "\sv*1"` ]]; then
|
||||
if [[ -n `$COMPOSE version | grep -E "\sv1"` ]]; then
|
||||
$COMPOSE version
|
||||
echo -e "${Error} ${RedBG} Docker-compose 版本过低,请升级至v2+!${Font}"
|
||||
error "Docker-compose 版本过低,请升级至v2+!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
@@ -91,7 +110,17 @@ check_docker() {
|
||||
check_node() {
|
||||
npm --version &> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${Error} ${RedBG} 未安装nodejs!${Font}"
|
||||
error "未安装 npm!"
|
||||
exit 1
|
||||
fi
|
||||
node --version &> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
error "未安装 Node.js!"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n `node --version | grep -E "v1"` ]]; then
|
||||
node --version
|
||||
error "Node.js 版本过低,请升级至v20+!"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
@@ -154,7 +183,7 @@ run_exec() {
|
||||
local cmd=$2
|
||||
local name=`docker_name $container`
|
||||
if [ -z "$name" ]; then
|
||||
echo -e "${Error} ${RedBG} 没有找到 $container 容器! ${Font}"
|
||||
error "没有找到 $container 容器!"
|
||||
exit 1
|
||||
fi
|
||||
docker exec -it "$name" /bin/sh -c "$cmd"
|
||||
@@ -170,7 +199,7 @@ run_mysql() {
|
||||
filename="${cur_path}/docker/mysql/backup/${database}_$(date "+%Y%m%d%H%M%S").sql.gz"
|
||||
run_exec mariadb "exec mysqldump --databases $database -u$username -p$password" | gzip > $filename
|
||||
judge "备份数据库"
|
||||
[ -f "$filename" ] && echo -e "备份文件:$filename"
|
||||
[ -f "$filename" ] && info "备份文件:$filename"
|
||||
elif [ "$1" = "recovery" ]; then
|
||||
database=$(env_get DB_DATABASE)
|
||||
username=$(env_get DB_USERNAME)
|
||||
@@ -179,19 +208,19 @@ run_mysql() {
|
||||
mkdir -p ${cur_path}/docker/mysql/backup
|
||||
list=`ls -1 "${cur_path}/docker/mysql/backup" | grep ".sql.gz"`
|
||||
if [ -z "$list" ]; then
|
||||
echo -e "${Error} ${RedBG} 没有备份文件!${Font}"
|
||||
error "没有备份文件!"
|
||||
exit 1
|
||||
fi
|
||||
echo "$list"
|
||||
read -rp "请输入备份文件名称还原:" inputname
|
||||
filename="${cur_path}/docker/mysql/backup/${inputname}"
|
||||
if [ ! -f "$filename" ]; then
|
||||
echo -e "${Error} ${RedBG} 备份文件:${inputname} 不存在! ${Font}"
|
||||
error "备份文件:${inputname} 不存在!"
|
||||
exit 1
|
||||
fi
|
||||
container_name=`docker_name mariadb`
|
||||
if [ -z "$container_name" ]; then
|
||||
echo -e "${Error} ${RedBG} 没有找到 mariadb 容器! ${Font}"
|
||||
error "没有找到 mariadb 容器!"
|
||||
exit 1
|
||||
fi
|
||||
docker cp $filename $container_name:/
|
||||
@@ -201,6 +230,49 @@ run_mysql() {
|
||||
fi
|
||||
}
|
||||
|
||||
https_auto() {
|
||||
restart_nginx="n"
|
||||
if [[ "$(env_get APP_PORT)" != "80" ]]; then
|
||||
warning "HTTP服务端口不是80,是否修改并继续操作? [Y/n]"
|
||||
read -r continue_http
|
||||
[[ -z ${continue_http} ]] && continue_http="Y"
|
||||
case $continue_http in
|
||||
[yY][eE][sS] | [yY])
|
||||
success "继续操作"
|
||||
env_set "APP_PORT" "80"
|
||||
restart_nginx="y"
|
||||
;;
|
||||
*)
|
||||
error "操作终止"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [[ "$(env_get APP_SSL_PORT)" != "443" ]]; then
|
||||
warning "HTTPS服务端口不是443,是否修改并继续操作? [Y/n]"
|
||||
read -r continue_https
|
||||
[[ -z ${continue_https} ]] && continue_https="Y"
|
||||
case $continue_https in
|
||||
[yY][eE][sS] | [yY])
|
||||
success "继续操作"
|
||||
env_set "APP_SSL_PORT" "443"
|
||||
restart_nginx="y"
|
||||
;;
|
||||
*)
|
||||
error "操作终止"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [[ "$restart_nginx" == "y" ]]; then
|
||||
$COMPOSE up -d
|
||||
fi
|
||||
docker run -it --rm -v $(pwd):/work nginx:alpine sh "/work/bin/https"
|
||||
if [[ 0 -eq $? ]]; then
|
||||
run_exec nginx "nginx -s reload"
|
||||
fi
|
||||
}
|
||||
|
||||
env_get() {
|
||||
local key=$1
|
||||
local value=`cat ${cur_path}/.env | grep "^$key=" | awk -F '=' '{print $2}'`
|
||||
@@ -220,7 +292,7 @@ env_set() {
|
||||
docker run -it --rm -v ${cur_path}:/www alpine sh -c "sed -i "/^${key}=/c\\${key}=${val}" /www/.env"
|
||||
fi
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${Error} ${RedBG} 设置env参数失败!${Font}"
|
||||
error "设置env参数失败!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -293,7 +365,7 @@ if [ $# -gt 0 ]; then
|
||||
run_exec php "composer config --unset repos.packagist"
|
||||
fi
|
||||
if [ ! -f "${cur_path}/vendor/autoload.php" ]; then
|
||||
echo -e "${Error} ${RedBG}composer install 失败,请重试! ${Font}"
|
||||
error "composer install 失败,请重试!"
|
||||
exit 1
|
||||
fi
|
||||
[[ -z "$(env_get APP_KEY)" ]] && run_exec php "php artisan key:generate"
|
||||
@@ -303,7 +375,7 @@ if [ $# -gt 0 ]; then
|
||||
while [ ! -f "${cur_path}/docker/mysql/data/$(env_get DB_DATABASE)/db.opt" ]; do
|
||||
((remaining=$remaining-1))
|
||||
if [ $remaining -lt 0 ]; then
|
||||
echo -e "${Error} ${RedBG} 数据库初始化失败! ${Font}"
|
||||
error "数据库初始化失败!"
|
||||
exit 1
|
||||
fi
|
||||
chmod -R 775 "${cur_path}/docker/mysql/data"
|
||||
@@ -311,19 +383,21 @@ if [ $# -gt 0 ]; then
|
||||
done
|
||||
run_exec php "php artisan migrate --seed"
|
||||
if [ ! -f "${cur_path}/docker/mysql/data/$(env_get DB_DATABASE)/$(env_get DB_PREFIX)migrations.ibd" ]; then
|
||||
echo -e "${Error} ${RedBG} 数据库安装失败! ${Font}"
|
||||
error "数据库安装失败!"
|
||||
exit 1
|
||||
fi
|
||||
# 设置初始化密码
|
||||
res=`run_exec mariadb "sh /etc/mysql/repassword.sh"`
|
||||
$COMPOSE up -d
|
||||
restart_php
|
||||
echo -e "${OK} ${GreenBG} 安装完成 ${Font}"
|
||||
echo -e "地址: http://${GreenBG}127.0.0.1:$(env_get APP_PORT)${Font}"
|
||||
echo -e "$res"
|
||||
success "安装完成"
|
||||
info "地址: http://${GreenBG}127.0.0.1:$(env_get APP_PORT)${Font}"
|
||||
info "$res"
|
||||
elif [[ "$1" == "update" ]]; then
|
||||
shift 1
|
||||
run_mysql backup
|
||||
if [[ "$@" != "nobackup" ]]; then
|
||||
run_mysql backup
|
||||
fi
|
||||
if [[ -z "$(arg_get local)" ]]; then
|
||||
git fetch --all
|
||||
git reset --hard origin/$(git branch | sed -n -e 's/^\* \(.*\)/\1/p')
|
||||
@@ -340,10 +414,10 @@ if [ $# -gt 0 ]; then
|
||||
[[ -z ${uninstall} ]] && uninstall="Y"
|
||||
case $uninstall in
|
||||
[yY][eE][sS] | [yY])
|
||||
echo -e "${RedBG} 开始卸载... ${Font}"
|
||||
info "${RedBG}开始卸载...${Font}"
|
||||
;;
|
||||
*)
|
||||
echo -e "${GreenBG} 终止卸载。 ${Font}"
|
||||
info "${GreenBG}终止卸载。${Font}"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
@@ -352,7 +426,7 @@ if [ $# -gt 0 ]; then
|
||||
rm -rf "./docker/mysql/data"
|
||||
rm -rf "./docker/log/supervisor"
|
||||
find "./storage/logs" -name "*.log" | xargs rm -rf
|
||||
echo -e "${OK} ${GreenBG} 卸载完成 ${Font}"
|
||||
success "卸载完成"
|
||||
elif [[ "$1" == "reinstall" ]]; then
|
||||
shift 1
|
||||
./cmd uninstall $@
|
||||
@@ -362,20 +436,20 @@ if [ $# -gt 0 ]; then
|
||||
shift 1
|
||||
env_set APP_PORT "$1"
|
||||
$COMPOSE up -d
|
||||
echo -e "${OK} ${GreenBG} 修改成功 ${Font}"
|
||||
echo -e "地址: http://${GreenBG}127.0.0.1:$(env_get APP_PORT)${Font}"
|
||||
success "修改成功"
|
||||
info "地址: http://${GreenBG}127.0.0.1:$(env_get APP_PORT)${Font}"
|
||||
elif [[ "$1" == "url" ]]; then
|
||||
shift 1
|
||||
env_set APP_URL "$1"
|
||||
restart_php
|
||||
echo -e "${OK} ${GreenBG} 修改成功 ${Font}"
|
||||
success "修改成功"
|
||||
elif [[ "$1" == "env" ]]; then
|
||||
shift 1
|
||||
if [ -n "$1" ]; then
|
||||
env_set $1 "$2"
|
||||
fi
|
||||
restart_php
|
||||
echo -e "${OK} ${GreenBG} 修改成功 ${Font}"
|
||||
success "修改成功"
|
||||
elif [[ "$1" == "repassword" ]]; then
|
||||
shift 1
|
||||
run_exec mariadb "sh /etc/mysql/repassword.sh \"$@\""
|
||||
@@ -391,6 +465,16 @@ if [ $# -gt 0 ]; then
|
||||
elif [[ "$1" == "electron" ]]; then
|
||||
shift 1
|
||||
run_electron $@
|
||||
elif [[ "$1" == "eeui" ]]; then
|
||||
shift 1
|
||||
cli="$@"
|
||||
por=""
|
||||
if [[ "$cli" == "build" ]]; then
|
||||
cli="build --simple"
|
||||
elif [[ "$cli" == "dev" ]]; then
|
||||
por="-p 8880:8880"
|
||||
fi
|
||||
docker run -it --rm -v ${cur_path}/resources/mobile:/work -w /work ${por} kuaifan/eeui-cli:0.0.1 eeui ${cli}
|
||||
elif [[ "$1" == "doc" ]]; then
|
||||
shift 1
|
||||
run_exec php "php app/Http/Controllers/Api/apidoc.php"
|
||||
@@ -398,13 +482,15 @@ if [ $# -gt 0 ]; then
|
||||
elif [[ "$1" == "debug" ]]; then
|
||||
shift 1
|
||||
switch_debug "$@"
|
||||
echo "success"
|
||||
info "success"
|
||||
elif [[ "$1" == "https" ]]; then
|
||||
shift 1
|
||||
if [[ "$@" == "auto" ]]; then
|
||||
if [[ "$1" == "agent" ]] || [[ "$1" == "true" ]]; then
|
||||
env_set APP_SCHEME "true"
|
||||
elif [[ "$1" == "close" ]] || [[ "$1" == "auto" ]]; then
|
||||
env_set APP_SCHEME "auto"
|
||||
else
|
||||
env_set APP_SCHEME "true"
|
||||
https_auto
|
||||
fi
|
||||
restart_php
|
||||
elif [[ "$1" == "artisan" ]]; then
|
||||
|
||||
950
composer.lock
generated
950
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Module\Base;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AllGroupMuteHandle extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$systemConfig = Base::setting('system');
|
||||
if ($systemConfig['all_group_mute'] == 'user' || $systemConfig['all_group_mute'] == 'all') {
|
||||
$systemConfig['all_group_mute'] = 'close';
|
||||
Base::setting('system', $systemConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ChangeCharsetToUtf8mb4 extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$pre = DB::connection()->getTablePrefix();
|
||||
$tables = [
|
||||
"approve_execution",
|
||||
"approve_execution_history",
|
||||
"approve_identitylink",
|
||||
"approve_identitylink_history",
|
||||
"approve_proc_inst",
|
||||
"approve_proc_inst_history",
|
||||
"approve_proc_msgs",
|
||||
"approve_procdef",
|
||||
"approve_procdef_history",
|
||||
"approve_task",
|
||||
"approve_task_history"
|
||||
];
|
||||
foreach ($tables as $table) {
|
||||
if (Schema::hasTable($table)) {
|
||||
Schema::getConnection()->getPdo()->exec("ALTER TABLE `{$pre}{$table}` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddWebSocketDialogUsersAddHide 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', 'hide')) {
|
||||
$table->integer('hide')->nullable()->default(0)->after('silence')->comment('不显示会话:0否,1是');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
|
||||
$table->dropColumn("hide");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddIndexSome20240315 extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msg_reads', function (Blueprint $table) {
|
||||
$table->index(['dialog_id', 'userid', 'read_at', 'msg_id'], 'IDEX_dialog_id_userid_read_at_msg_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return voidw
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msg_reads', function (Blueprint $table) {
|
||||
$table->dropIndex('IDEX_dialog_id_userid_read_at_msg_id');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Models\WebSocketDialogUser;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddWebSocketDialogUsersLastAt extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$isAdd = false;
|
||||
Schema::table('web_socket_dialog_users', function (Blueprint $table) use (&$isAdd) {
|
||||
if (!Schema::hasColumn('web_socket_dialog_users', 'last_at')) {
|
||||
$isAdd = true;
|
||||
$table->timestamp('last_at')->nullable()->after('top_at')->comment('最后消息时间');
|
||||
}
|
||||
});
|
||||
if ($isAdd) {
|
||||
// 更新数据
|
||||
WebSocketDialog::chunk(100, function ($dialogs) {
|
||||
/** @var WebSocketDialog $dialog */
|
||||
foreach ($dialogs as $dialog) {
|
||||
WebSocketDialogUser::whereDialogId($dialog->id)->update(['last_at' => $dialog->last_at]);
|
||||
}
|
||||
});
|
||||
|
||||
// 删除表字段
|
||||
Schema::table('web_socket_dialogs', function (Blueprint $table) {
|
||||
$table->dropColumn("last_at");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// 回滚数据 - 无法回滚
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddIndexSome20240317 extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
|
||||
$table->dropIndex(['userid']);
|
||||
$table->index(['userid', 'dialog_id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return voidw
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// 回滚数据 - 无法回滚
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use App\Module\Base;
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ChangeForwardData extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('web_socket_dialog_msgs', 'forward_show')) {
|
||||
WebSocketDialogMsg::where("forward_id", ">", 0)->chunk(100, function ($items) {
|
||||
/** @var WebSocketDialogMsg $item */
|
||||
foreach ($items as $item) {
|
||||
$msg = Base::json2array($item->getRawOriginal('msg'));
|
||||
$msg['forward_data'] = [
|
||||
'id' => $item->forward_id,
|
||||
'userid' => 0,
|
||||
'parent_id' => $item->forward_id,
|
||||
'parent_userid' => 0,
|
||||
'show' => 0,
|
||||
];
|
||||
$original = WebSocketDialogMsg::select(['id', 'userid', 'forward_show'])->whereId($item->forward_id)->withTrashed()->first();
|
||||
if ($original) {
|
||||
$msg['forward_data']['userid'] = $original->userid;
|
||||
$msg['forward_data']['parent_userid'] = $original->userid;
|
||||
$msg['forward_data']['show'] = $original->forward_show;
|
||||
}
|
||||
$item->msg = Base::array2json($msg);
|
||||
$item->save();
|
||||
}
|
||||
});
|
||||
$table->dropColumn("forward_show");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// 回滚数据 - 无法回滚
|
||||
}
|
||||
}
|
||||
49
database/migrations/2024_03_18_153504_change_reply_data.php
Normal file
49
database/migrations/2024_03_18_153504_change_reply_data.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
use App\Module\Base;
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class ChangeReplyData extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
WebSocketDialogMsg::where("reply_id", ">", 0)->chunk(100, function ($items) {
|
||||
/** @var WebSocketDialogMsg $item */
|
||||
foreach ($items as $item) {
|
||||
$msg = Base::json2array($item->getRawOriginal('msg'));
|
||||
$msg['reply_data'] = [
|
||||
'id' => $item->reply_id,
|
||||
'userid' => 0,
|
||||
'type' => '',
|
||||
'msg' => [],
|
||||
];
|
||||
$original = WebSocketDialogMsg::whereId($item->reply_id)->withTrashed()->first();
|
||||
if ($original) {
|
||||
$replyMsg = Base::json2array($original->getRawOriginal('msg'));
|
||||
unset($replyMsg['reply_data']);
|
||||
$msg['reply_data']['userid'] = $original->userid;
|
||||
$msg['reply_data']['type'] = $original->type;
|
||||
$msg['reply_data']['msg'] = $replyMsg;
|
||||
}
|
||||
$item->msg = Base::array2json($msg);
|
||||
$item->save();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// 回滚数据 - 无法回滚
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddUmengAliasDevice extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
//
|
||||
Schema::table('umeng_alias', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('umeng_alias', 'device')) {
|
||||
$table->text('ua')->nullable()->after('platform')->comment('userAgent');
|
||||
$table->string('device', 100)->nullable()->default('')->after('platform')->comment('设备类型');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
Schema::table('umeng_alias', function (Blueprint $table) {
|
||||
$table->dropColumn("ua");
|
||||
$table->dropColumn("device");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Models\WebSocketDialogUser;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
@@ -19,8 +20,7 @@ class GenerateWebSocketDialogsDefaultGroup extends Migration
|
||||
if ($botUser) {
|
||||
$dialog = WebSocketDialog::checkUserDialog($botUser, 1);
|
||||
if ($dialog) {
|
||||
$dialog->last_at = Carbon::now();
|
||||
$dialog->save();
|
||||
WebSocketDialogUser::whereDialogId($dialog->id)->update(['last_at' => Carbon::now()]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateMeetingMsgsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::dropIfExists('meeting_msgs');
|
||||
Schema::create('meeting_msgs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('meetingid')->nullable()->default('')->comment('会议ID');
|
||||
$table->bigInteger('dialog_id')->nullable()->default(0)->comment('对话ID');
|
||||
$table->bigInteger('msg_id')->nullable()->default(0)->comment('消息ID');
|
||||
});
|
||||
\DB::table('meetings')->update(['end_at' => null]);
|
||||
WebSocketDialogMsg::whereType('meeting')->chunk(100, function ($msgs) {
|
||||
/** @var WebSocketDialogMsg $msg */
|
||||
foreach ($msgs as $msg) {
|
||||
$meetingid = $msg->msg['meetingid'];
|
||||
$dialog_id = $msg->dialog_id;
|
||||
$msg_id = $msg->id;
|
||||
\DB::table('meeting_msgs')->insert(compact('meetingid', 'dialog_id', 'msg_id'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('meeting_msgs');
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 1,
|
||||
'dialog_id' => 1,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 10:46:37'),
|
||||
'created_at' => seeders_at('2021-07-01 10:46:37'),
|
||||
'updated_at' => seeders_at('2021-07-01 10:46:37'),
|
||||
),
|
||||
@@ -34,6 +35,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 2,
|
||||
'dialog_id' => 1,
|
||||
'userid' => 2,
|
||||
'last_at' => seeders_at('2021-07-01 10:46:37'),
|
||||
'created_at' => seeders_at('2021-07-01 10:46:37'),
|
||||
'updated_at' => seeders_at('2021-07-01 10:46:37'),
|
||||
),
|
||||
@@ -42,6 +44,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 3,
|
||||
'dialog_id' => 2,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 10:46:47'),
|
||||
'created_at' => seeders_at('2021-07-01 10:46:47'),
|
||||
'updated_at' => seeders_at('2021-07-01 10:46:47'),
|
||||
),
|
||||
@@ -50,6 +53,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 4,
|
||||
'dialog_id' => 3,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 10:46:47'),
|
||||
'created_at' => seeders_at('2021-07-01 10:46:47'),
|
||||
'updated_at' => seeders_at('2021-07-01 10:46:47'),
|
||||
),
|
||||
@@ -58,6 +62,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 5,
|
||||
'dialog_id' => 4,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 10:47:45'),
|
||||
'created_at' => seeders_at('2021-07-01 10:47:45'),
|
||||
'updated_at' => seeders_at('2021-07-01 10:47:45'),
|
||||
),
|
||||
@@ -66,6 +71,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 6,
|
||||
'dialog_id' => 5,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 10:47:45'),
|
||||
'created_at' => seeders_at('2021-07-01 10:47:45'),
|
||||
'updated_at' => seeders_at('2021-07-01 10:47:45'),
|
||||
),
|
||||
@@ -74,6 +80,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 7,
|
||||
'dialog_id' => 6,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 11:02:57'),
|
||||
'created_at' => seeders_at('2021-07-01 11:02:57'),
|
||||
'updated_at' => seeders_at('2021-07-01 11:02:57'),
|
||||
),
|
||||
@@ -82,6 +89,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 8,
|
||||
'dialog_id' => 7,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 11:02:57'),
|
||||
'created_at' => seeders_at('2021-07-01 11:02:57'),
|
||||
'updated_at' => seeders_at('2021-07-01 11:02:57'),
|
||||
),
|
||||
@@ -90,6 +98,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 9,
|
||||
'dialog_id' => 8,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 11:43:01'),
|
||||
'created_at' => seeders_at('2021-07-01 11:43:01'),
|
||||
'updated_at' => seeders_at('2021-07-01 11:43:01'),
|
||||
),
|
||||
@@ -98,6 +107,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 10,
|
||||
'dialog_id' => 9,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 11:43:01'),
|
||||
'created_at' => seeders_at('2021-07-01 11:43:01'),
|
||||
'updated_at' => seeders_at('2021-07-01 11:43:01'),
|
||||
),
|
||||
@@ -106,6 +116,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 11,
|
||||
'dialog_id' => 10,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 15:33:23'),
|
||||
'created_at' => seeders_at('2021-07-01 15:33:23'),
|
||||
'updated_at' => seeders_at('2021-07-01 15:33:23'),
|
||||
),
|
||||
@@ -114,6 +125,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 12,
|
||||
'dialog_id' => 11,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 15:33:23'),
|
||||
'created_at' => seeders_at('2021-07-01 15:33:23'),
|
||||
'updated_at' => seeders_at('2021-07-01 15:33:23'),
|
||||
),
|
||||
@@ -122,6 +134,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 13,
|
||||
'dialog_id' => 12,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 15:37:06'),
|
||||
'created_at' => seeders_at('2021-07-01 15:37:06'),
|
||||
'updated_at' => seeders_at('2021-07-01 15:37:06'),
|
||||
),
|
||||
@@ -130,6 +143,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 14,
|
||||
'dialog_id' => 13,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 15:37:06'),
|
||||
'created_at' => seeders_at('2021-07-01 15:37:06'),
|
||||
'updated_at' => seeders_at('2021-07-01 15:37:06'),
|
||||
),
|
||||
@@ -138,6 +152,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 15,
|
||||
'dialog_id' => 14,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 16:15:28'),
|
||||
'created_at' => seeders_at('2021-07-01 16:15:28'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:15:28'),
|
||||
),
|
||||
@@ -146,6 +161,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 16,
|
||||
'dialog_id' => 15,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 16:15:28'),
|
||||
'created_at' => seeders_at('2021-07-01 16:15:28'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:15:28'),
|
||||
),
|
||||
@@ -154,6 +170,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 17,
|
||||
'dialog_id' => 7,
|
||||
'userid' => 2,
|
||||
'last_at' => seeders_at('2021-07-01 16:22:42'),
|
||||
'created_at' => seeders_at('2021-07-01 16:22:42'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:22:42'),
|
||||
),
|
||||
@@ -162,6 +179,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 18,
|
||||
'dialog_id' => 5,
|
||||
'userid' => 2,
|
||||
'last_at' => seeders_at('2021-07-01 16:23:15'),
|
||||
'created_at' => seeders_at('2021-07-01 16:23:15'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:23:15'),
|
||||
),
|
||||
@@ -170,6 +188,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 19,
|
||||
'dialog_id' => 15,
|
||||
'userid' => 2,
|
||||
'last_at' => seeders_at('2021-07-01 16:23:40'),
|
||||
'created_at' => seeders_at('2021-07-01 16:23:40'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:23:40'),
|
||||
),
|
||||
@@ -178,6 +197,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 20,
|
||||
'dialog_id' => 11,
|
||||
'userid' => 2,
|
||||
'last_at' => seeders_at('2021-07-01 16:29:38'),
|
||||
'created_at' => seeders_at('2021-07-01 16:29:38'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:29:38'),
|
||||
),
|
||||
@@ -186,6 +206,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 21,
|
||||
'dialog_id' => 16,
|
||||
'userid' => 2,
|
||||
'last_at' => seeders_at('2021-07-01 16:56:05'),
|
||||
'created_at' => seeders_at('2021-07-01 16:56:05'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:56:05'),
|
||||
),
|
||||
@@ -194,6 +215,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 22,
|
||||
'dialog_id' => 16,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 16:56:05'),
|
||||
'created_at' => seeders_at('2021-07-01 16:56:05'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:56:05'),
|
||||
),
|
||||
@@ -202,6 +224,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 23,
|
||||
'dialog_id' => 17,
|
||||
'userid' => 2,
|
||||
'last_at' => seeders_at('2021-07-01 16:56:35'),
|
||||
'created_at' => seeders_at('2021-07-01 16:56:35'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:56:35'),
|
||||
),
|
||||
@@ -210,6 +233,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 24,
|
||||
'dialog_id' => 17,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 16:56:35'),
|
||||
'created_at' => seeders_at('2021-07-01 16:56:35'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:56:35'),
|
||||
),
|
||||
@@ -218,6 +242,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 25,
|
||||
'dialog_id' => 18,
|
||||
'userid' => 2,
|
||||
'last_at' => seeders_at('2021-07-01 16:56:57'),
|
||||
'created_at' => seeders_at('2021-07-01 16:56:57'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:56:57'),
|
||||
),
|
||||
@@ -226,6 +251,7 @@ class WebSocketDialogUsersTableSeeder extends Seeder
|
||||
'id' => 26,
|
||||
'dialog_id' => 18,
|
||||
'userid' => 1,
|
||||
'last_at' => seeders_at('2021-07-01 16:56:57'),
|
||||
'created_at' => seeders_at('2021-07-01 16:56:57'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:56:57'),
|
||||
),
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Database\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Models\WebSocketDialogUser;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
@@ -30,7 +31,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'user',
|
||||
'group_type' => '',
|
||||
'name' => '',
|
||||
'last_at' => seeders_at('2021-07-01 17:12:52'),
|
||||
'created_at' => seeders_at('2021-07-01 10:46:37'),
|
||||
'updated_at' => seeders_at('2021-07-01 17:12:52'),
|
||||
'deleted_at' => NULL,
|
||||
@@ -41,7 +41,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => NULL,
|
||||
'created_at' => seeders_at('2021-07-01 10:46:47'),
|
||||
'updated_at' => seeders_at('2021-07-01 17:31:03'),
|
||||
'deleted_at' => seeders_at('2021-07-01 17:31:03'),
|
||||
@@ -52,7 +51,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => NULL,
|
||||
'created_at' => seeders_at('2021-07-01 10:46:47'),
|
||||
'updated_at' => seeders_at('2021-07-01 10:46:55'),
|
||||
'deleted_at' => seeders_at('2021-07-01 10:46:55'),
|
||||
@@ -63,7 +61,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => NULL,
|
||||
'created_at' => seeders_at('2021-07-01 10:47:45'),
|
||||
'updated_at' => seeders_at('2021-07-01 17:30:05'),
|
||||
'deleted_at' => seeders_at('2021-07-01 17:30:05'),
|
||||
@@ -74,7 +71,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => seeders_at('2021-07-01 16:31:58'),
|
||||
'created_at' => seeders_at('2021-07-01 10:47:45'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:31:58'),
|
||||
'deleted_at' => NULL,
|
||||
@@ -85,7 +81,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => NULL,
|
||||
'created_at' => seeders_at('2021-07-01 11:02:57'),
|
||||
'updated_at' => seeders_at('2021-07-01 17:31:28'),
|
||||
'deleted_at' => seeders_at('2021-07-01 17:31:28'),
|
||||
@@ -96,7 +91,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => seeders_at('2021-07-01 16:32:50'),
|
||||
'created_at' => seeders_at('2021-07-01 11:02:57'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:32:50'),
|
||||
'deleted_at' => NULL,
|
||||
@@ -107,7 +101,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => NULL,
|
||||
'created_at' => seeders_at('2021-07-01 11:43:01'),
|
||||
'updated_at' => seeders_at('2021-07-01 17:31:28'),
|
||||
'deleted_at' => seeders_at('2021-07-01 17:31:28'),
|
||||
@@ -118,7 +111,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => seeders_at('2021-07-01 14:02:57'),
|
||||
'created_at' => seeders_at('2021-07-01 11:43:01'),
|
||||
'updated_at' => seeders_at('2021-07-01 14:02:57'),
|
||||
'deleted_at' => NULL,
|
||||
@@ -129,7 +121,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => NULL,
|
||||
'created_at' => seeders_at('2021-07-01 15:33:23'),
|
||||
'updated_at' => seeders_at('2021-07-01 17:31:28'),
|
||||
'deleted_at' => seeders_at('2021-07-01 17:31:28'),
|
||||
@@ -140,7 +131,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => seeders_at('2021-07-01 16:31:40'),
|
||||
'created_at' => seeders_at('2021-07-01 15:33:23'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:31:40'),
|
||||
'deleted_at' => NULL,
|
||||
@@ -151,7 +141,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => NULL,
|
||||
'created_at' => seeders_at('2021-07-01 15:37:06'),
|
||||
'updated_at' => seeders_at('2021-07-01 17:31:28'),
|
||||
'deleted_at' => seeders_at('2021-07-01 17:31:28'),
|
||||
@@ -162,7 +151,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => seeders_at('2021-07-01 15:44:09'),
|
||||
'created_at' => seeders_at('2021-07-01 15:37:06'),
|
||||
'updated_at' => seeders_at('2021-07-01 15:44:09'),
|
||||
'deleted_at' => NULL,
|
||||
@@ -173,7 +161,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => NULL,
|
||||
'created_at' => seeders_at('2021-07-01 16:15:28'),
|
||||
'updated_at' => seeders_at('2021-07-01 17:31:28'),
|
||||
'deleted_at' => seeders_at('2021-07-01 17:31:28'),
|
||||
@@ -184,7 +171,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'project',
|
||||
'name' => '',
|
||||
'last_at' => seeders_at('2021-07-01 16:37:59'),
|
||||
'created_at' => seeders_at('2021-07-01 16:15:28'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:37:59'),
|
||||
'deleted_at' => NULL,
|
||||
@@ -195,7 +181,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'task',
|
||||
'name' => '',
|
||||
'last_at' => seeders_at('2021-07-01 16:58:02'),
|
||||
'created_at' => seeders_at('2021-07-01 16:56:05'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:58:02'),
|
||||
'deleted_at' => NULL,
|
||||
@@ -206,7 +191,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'task',
|
||||
'name' => '',
|
||||
'last_at' => seeders_at('2021-07-01 16:57:58'),
|
||||
'created_at' => seeders_at('2021-07-01 16:56:35'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:57:58'),
|
||||
'deleted_at' => NULL,
|
||||
@@ -217,7 +201,6 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
'type' => 'group',
|
||||
'group_type' => 'task',
|
||||
'name' => '',
|
||||
'last_at' => seeders_at('2021-07-01 16:57:52'),
|
||||
'created_at' => seeders_at('2021-07-01 16:56:57'),
|
||||
'updated_at' => seeders_at('2021-07-01 16:57:52'),
|
||||
'deleted_at' => NULL,
|
||||
@@ -228,8 +211,7 @@ class WebSocketDialogsTableSeeder extends Seeder
|
||||
if ($botUser) {
|
||||
$dialog = WebSocketDialog::checkUserDialog($botUser, 1);
|
||||
if ($dialog) {
|
||||
$dialog->last_at = Carbon::now();
|
||||
$dialog->save();
|
||||
WebSocketDialogUser::whereDialogId($dialog->id)->change(['last_at' => Carbon::now()->subSecond()]);
|
||||
}
|
||||
}
|
||||
User::botGetOrCreate('ai-openai');
|
||||
|
||||
@@ -36,6 +36,7 @@ services:
|
||||
image: "nginx:alpine"
|
||||
ports:
|
||||
- "${APP_PORT}:80"
|
||||
- "${APP_SSL_PORT:-}:443"
|
||||
volumes:
|
||||
- ./docker/nginx:/etc/nginx/conf.d
|
||||
- ./public:/var/www/public
|
||||
@@ -103,7 +104,7 @@ services:
|
||||
|
||||
fileview:
|
||||
container_name: "dootask-fileview-${APP_ID}"
|
||||
image: "kuaifan/fileview:4.2.0-SNAPSHOT-RC22"
|
||||
image: "kuaifan/fileview:4.2.0-SNAPSHOT-RC25"
|
||||
environment:
|
||||
KK_CONTEXT_PATH: "/fileview"
|
||||
KK_OFFICE_PREVIEW_SWITCH_DISABLED: true
|
||||
@@ -160,6 +161,7 @@ services:
|
||||
MYSQL_PASSWORD: "${DB_PASSWORD}"
|
||||
MYSQL_Prefix: "${DB_PREFIX}approve_"
|
||||
DEMO_DATA: true
|
||||
KEY: ${APP_KEY}
|
||||
networks:
|
||||
extnetwork:
|
||||
ipv4_address: "${APP_IPPR}.11"
|
||||
@@ -169,7 +171,7 @@ services:
|
||||
|
||||
ai:
|
||||
container_name: "dootask-ai-${APP_ID}"
|
||||
image: "kuaifan/dooai:0.0.8"
|
||||
image: "kuaifan/dooai:0.1.8"
|
||||
networks:
|
||||
extnetwork:
|
||||
ipv4_address: "${APP_IPPR}.12"
|
||||
@@ -177,7 +179,7 @@ services:
|
||||
|
||||
okr:
|
||||
container_name: "dootask-okr-${APP_ID}"
|
||||
image: "kuaifan/doookr:0.0.26"
|
||||
image: "kuaifan/doookr:0.4.2"
|
||||
environment:
|
||||
TZ: "${TIMEZONE:-PRC}"
|
||||
DOO_TASK_URL: "http://${APP_IPPR}.3"
|
||||
@@ -186,7 +188,9 @@ services:
|
||||
MYSQL_DBNAME: "${DB_DATABASE}"
|
||||
MYSQL_USERNAME: "${DB_USERNAME}"
|
||||
MYSQL_PASSWORD: "${DB_PASSWORD}"
|
||||
MYSQL_PREFIX: "${DB_PREFIX}"
|
||||
DEMO_DATA: true
|
||||
KEY: ${APP_KEY}
|
||||
networks:
|
||||
extnetwork:
|
||||
ipv4_address: "${APP_IPPR}.13"
|
||||
|
||||
@@ -12,7 +12,7 @@ default_storage_engine = InnoDB
|
||||
performance_schema_max_table_instances = 400
|
||||
table_definition_cache = 400
|
||||
key_buffer_size = 1024M
|
||||
max_allowed_packet = 10G
|
||||
max_allowed_packet = 8192M
|
||||
table_open_cache = 2048
|
||||
sort_buffer_size = 4096K
|
||||
net_buffer_length = 4K
|
||||
@@ -47,7 +47,7 @@ innodb_write_io_threads = 2
|
||||
|
||||
[mysqldump]
|
||||
quick
|
||||
max_allowed_packet = 500M
|
||||
max_allowed_packet = 8192M
|
||||
|
||||
[mysql]
|
||||
no-auto-rehash
|
||||
|
||||
1
docker/nginx/.gitignore
vendored
1
docker/nginx/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
site
|
||||
2
docker/nginx/conf.d/.gitignore
vendored
2
docker/nginx/conf.d/.gitignore
vendored
@@ -1 +1 @@
|
||||
/*.conf
|
||||
!.gitignore
|
||||
|
||||
1
docker/nginx/site/.gitignore
vendored
Normal file
1
docker/nginx/site/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!.gitignore
|
||||
1
docker/office/resources/require.js
vendored
1
docker/office/resources/require.js
vendored
@@ -52,7 +52,6 @@
|
||||
window._disableDownload = setInterval(function() {
|
||||
var downloadBtn = document.getElementById("slot-hbtn-download")
|
||||
if(downloadBtn) {
|
||||
console.log(1)
|
||||
clearInterval(window._disableDownload);
|
||||
document.getElementById("slot-hbtn-download")?.remove()
|
||||
document.getElementById("fm-btn-download")?.remove()
|
||||
|
||||
25
electron/build.js
vendored
25
electron/build.js
vendored
@@ -126,6 +126,16 @@ function genericPublish({url, key, version, output}) {
|
||||
if (err) {
|
||||
console.warn(err)
|
||||
} else {
|
||||
let uploadFileNum = 0;
|
||||
for (const filename of files) {
|
||||
const localFile = path.join(filePath, filename)
|
||||
if (fs.existsSync(localFile)) {
|
||||
const fileStat = fs.statSync(localFile)
|
||||
if (fileStat.isFile()) {
|
||||
uploadFileNum += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
const uploadOras = {}
|
||||
for (const filename of files) {
|
||||
const localFile = path.join(filePath, filename)
|
||||
@@ -135,6 +145,7 @@ function genericPublish({url, key, version, output}) {
|
||||
uploadOras[filename] = ora(`Upload [0%] ${filename}`).start()
|
||||
const formData = new FormData()
|
||||
formData.append("file", fs.createReadStream(localFile));
|
||||
formData.append("file_num", uploadFileNum);
|
||||
await axiosAutoTry({
|
||||
axios: {
|
||||
method: 'post',
|
||||
@@ -203,8 +214,6 @@ function startBuild(data) {
|
||||
fs.writeFileSync(electronDir + "/config.js", "window.systemInfo = " + JSON.stringify(systemInfo), 'utf8');
|
||||
fs.writeFileSync(nativeCachePath, utils.formatUrl(data.url));
|
||||
fs.writeFileSync(devloadCachePath, "", 'utf8');
|
||||
// default (fix "Failed to load resource: net::ERR_FILE_NOT_FOUND" report)
|
||||
fs.writeFileSync(electronDir + "/default", "default", 'utf8');
|
||||
// index.html
|
||||
let manifestFile = path.resolve(electronDir, "manifest.json");
|
||||
if (!fs.existsSync(manifestFile)) {
|
||||
@@ -220,14 +229,16 @@ function startBuild(data) {
|
||||
fs.writeFileSync(indexFile, indexString, 'utf8');
|
||||
//
|
||||
if (data.id === 'app') {
|
||||
const eeuiDir = path.resolve(__dirname, "../resources/mobile");
|
||||
const eeuiCli = "kuaifan/eeui-cli:0.0.1"
|
||||
const publicDir = path.resolve(__dirname, "../resources/mobile/src/public");
|
||||
fse.removeSync(publicDir)
|
||||
fse.copySync(electronDir, publicDir)
|
||||
if (argv[3] === "setting") {
|
||||
child_process.spawnSync("eeui", ["setting"], {stdio: "inherit", cwd: "resources/mobile"});
|
||||
child_process.spawnSync("docker", `run -it --rm -v ${eeuiDir}:/work -w /work ${eeuiCli} eeui setting`.split(" "), {stdio: "inherit", cwd: "resources/mobile"});
|
||||
}
|
||||
if (['setting', 'build'].includes(argv[3])) {
|
||||
child_process.spawnSync("eeui", ["build", "--simple"], {stdio: "inherit", cwd: "resources/mobile"});
|
||||
child_process.spawnSync("docker", `run -it --rm -v ${eeuiDir}:/work -w /work ${eeuiCli} eeui build --simple`.split(" "), {stdio: "inherit", cwd: "resources/mobile"});
|
||||
} else {
|
||||
[
|
||||
path.resolve(publicDir, "../../platforms/ios/eeuiApp/bundlejs/eeui/public"),
|
||||
@@ -327,9 +338,11 @@ if (["dev"].includes(argv[2])) {
|
||||
notarize: false,
|
||||
}
|
||||
}, false, false)
|
||||
} else if (["all"].includes(argv[2])) {
|
||||
} else if (["all", "win", "mac"].includes(argv[2])) {
|
||||
// 自动编译
|
||||
platforms.forEach(platform => {
|
||||
platforms.filter(p => {
|
||||
return argv[2] === "all" || p.indexOf(argv[2]) !== -1
|
||||
}).forEach(platform => {
|
||||
config.app.forEach(data => {
|
||||
data.configure = {
|
||||
platform,
|
||||
|
||||
3
electron/electron-preload.js
vendored
3
electron/electron-preload.js
vendored
@@ -72,6 +72,7 @@ contextBridge.exposeInMainWorld(
|
||||
contextBridge.exposeInMainWorld(
|
||||
'process', {
|
||||
type: process.type,
|
||||
versions: process.versions
|
||||
versions: process.versions,
|
||||
platform: process.platform,
|
||||
}
|
||||
);
|
||||
|
||||
522
electron/electron.js
vendored
522
electron/electron.js
vendored
@@ -1,9 +1,11 @@
|
||||
const fs = require('fs')
|
||||
const os = require("os");
|
||||
const path = require('path')
|
||||
const {app, BrowserWindow, ipcMain, dialog, clipboard, nativeImage, shell, Tray, Menu, globalShortcut, Notification} = require('electron')
|
||||
const {app, BrowserWindow, ipcMain, dialog, clipboard, nativeImage, shell, Tray, Menu, globalShortcut, Notification, BrowserView, nativeTheme} = require('electron')
|
||||
const {autoUpdater} = require("electron-updater")
|
||||
const log = require("electron-log");
|
||||
const electronConf = require('electron-config')
|
||||
const userConf = new electronConf()
|
||||
const fsProm = require('fs/promises');
|
||||
const PDFDocument = require('pdf-lib').PDFDocument;
|
||||
const Screenshots = require("electron-screenshots-tool").Screenshots;
|
||||
@@ -17,13 +19,13 @@ const spawn = require("child_process").spawn;
|
||||
const isMac = process.platform === 'darwin'
|
||||
const isWin = process.platform === 'win32'
|
||||
const allowedUrls = /^(?:https?|mailto|tel|callto):/i;
|
||||
const allowedCalls = /^(?:mailto|tel|callto):/i;
|
||||
let enableStoreBkp = true;
|
||||
let dialogOpen = false;
|
||||
let enablePlugins = false;
|
||||
|
||||
let mainWindow = null,
|
||||
mainTray = null,
|
||||
subWindow = [],
|
||||
isReady = false,
|
||||
willQuitApp = false,
|
||||
devloadUrl = "",
|
||||
@@ -32,6 +34,20 @@ let mainWindow = null,
|
||||
let screenshotObj = null,
|
||||
screenshotKey = null;
|
||||
|
||||
let childWindow = [],
|
||||
webTabWindow = null,
|
||||
webTabView = [],
|
||||
webTabHeight = 38;
|
||||
|
||||
let showState = {},
|
||||
onShowWindow = (win) => {
|
||||
if (typeof showState[win.webContents.id] === 'undefined') {
|
||||
showState[win.webContents.id] = true
|
||||
win.setBackgroundColor('rgba(255, 255, 255, 0)')
|
||||
win.show();
|
||||
}
|
||||
}
|
||||
|
||||
if (fs.existsSync(devloadCachePath)) {
|
||||
devloadUrl = fs.readFileSync(devloadCachePath, 'utf8')
|
||||
}
|
||||
@@ -43,6 +59,8 @@ function createMainWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 1280,
|
||||
height: 800,
|
||||
minWidth: 360,
|
||||
minHeight: 360,
|
||||
center: true,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
@@ -56,19 +74,20 @@ function createMainWindow() {
|
||||
const originalUA = mainWindow.webContents.session.getUserAgent() || mainWindow.webContents.getUserAgent()
|
||||
mainWindow.webContents.setUserAgent(originalUA + " MainTaskWindow/" + process.platform + "/" + os.arch() + "/1.0");
|
||||
mainWindow.webContents.setWindowOpenHandler(({url}) => {
|
||||
openExternal(url)
|
||||
if (allowedCalls.test(url)) {
|
||||
return {action: 'allow'}
|
||||
}
|
||||
utils.onBeforeOpenWindow(mainWindow.webContents, url).then(() => {
|
||||
openExternal(url)
|
||||
})
|
||||
return {action: 'deny'}
|
||||
})
|
||||
electronMenu.webContentsMenu(mainWindow.webContents)
|
||||
|
||||
if (devloadUrl) {
|
||||
mainWindow.loadURL(devloadUrl).then(_ => {
|
||||
|
||||
})
|
||||
mainWindow.loadURL(devloadUrl).then(_ => { }).catch(_ => { })
|
||||
} else {
|
||||
mainWindow.loadFile('./public/index.html').then(_ => {
|
||||
|
||||
})
|
||||
mainWindow.loadFile('./public/index.html').then(_ => { }).catch(_ => { })
|
||||
}
|
||||
|
||||
mainWindow.on('page-title-updated', (event, title) => {
|
||||
@@ -96,7 +115,7 @@ function createMainWindow() {
|
||||
* 创建子窗口
|
||||
* @param args {path, hash, title, titleFixed, force, userAgent, config, webPreferences}
|
||||
*/
|
||||
function createSubWindow(args) {
|
||||
function createChildWindow(args) {
|
||||
if (!args) {
|
||||
return;
|
||||
}
|
||||
@@ -106,7 +125,7 @@ function createSubWindow(args) {
|
||||
}
|
||||
|
||||
let name = args.name || "auto_" + utils.randomString(6);
|
||||
let item = subWindow.find(item => item.name == name);
|
||||
let item = childWindow.find(item => item.name == name);
|
||||
let browser = item ? item.browser : null;
|
||||
if (browser) {
|
||||
browser.focus();
|
||||
@@ -119,7 +138,10 @@ function createSubWindow(args) {
|
||||
browser = new BrowserWindow(Object.assign({
|
||||
width: 1280,
|
||||
height: 800,
|
||||
minWidth: 360,
|
||||
minHeight: 360,
|
||||
center: true,
|
||||
show: false,
|
||||
parent: mainWindow,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: Object.assign({
|
||||
@@ -146,34 +168,49 @@ function createSubWindow(args) {
|
||||
})
|
||||
|
||||
browser.on('closed', () => {
|
||||
let index = subWindow.findIndex(item => item.name == name);
|
||||
let index = childWindow.findIndex(item => item.name == name);
|
||||
if (index > -1) {
|
||||
subWindow.splice(index, 1)
|
||||
childWindow.splice(index, 1)
|
||||
}
|
||||
})
|
||||
|
||||
subWindow.push({ name, browser })
|
||||
browser.once('ready-to-show', () => {
|
||||
onShowWindow(browser);
|
||||
})
|
||||
|
||||
browser.webContents.once('dom-ready', () => {
|
||||
onShowWindow(browser);
|
||||
})
|
||||
|
||||
childWindow.push({ name, browser })
|
||||
}
|
||||
const originalUA = browser.webContents.session.getUserAgent() || browser.webContents.getUserAgent()
|
||||
browser.webContents.setUserAgent(originalUA + " SubTaskWindow/" + process.platform + "/" + os.arch() + "/1.0" + (args.userAgent ? (" " + args.userAgent) : ""));
|
||||
browser.webContents.setWindowOpenHandler(({url}) => {
|
||||
openExternal(url)
|
||||
if (allowedCalls.test(url)) {
|
||||
return {action: 'allow'}
|
||||
}
|
||||
utils.onBeforeOpenWindow(browser.webContents, url).then(() => {
|
||||
openExternal(url)
|
||||
})
|
||||
return {action: 'deny'}
|
||||
})
|
||||
electronMenu.webContentsMenu(browser.webContents)
|
||||
|
||||
const hash = args.hash || args.path;
|
||||
if (devloadUrl) {
|
||||
browser.loadURL(devloadUrl + '#' + hash).then(_ => {
|
||||
|
||||
})
|
||||
} else {
|
||||
browser.loadFile('./public/index.html', {
|
||||
hash
|
||||
}).then(_ => {
|
||||
|
||||
})
|
||||
if (/^https?:\/\//i.test(hash)) {
|
||||
browser.loadURL(hash).then(_ => { }).catch(_ => { })
|
||||
return;
|
||||
}
|
||||
if (devloadUrl) {
|
||||
browser.loadURL(devloadUrl + '#' + hash).then(_ => { }).catch(_ => { })
|
||||
return;
|
||||
}
|
||||
browser.loadFile('./public/index.html', {
|
||||
hash
|
||||
}).then(_ => {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,7 +218,7 @@ function createSubWindow(args) {
|
||||
* @param browser
|
||||
* @param args
|
||||
*/
|
||||
function updateSubWindow(browser, args) {
|
||||
function updateChildWindow(browser, args) {
|
||||
if (!args) {
|
||||
return;
|
||||
}
|
||||
@@ -193,25 +230,345 @@ function updateSubWindow(browser, args) {
|
||||
const hash = args.hash || args.path;
|
||||
if (hash) {
|
||||
if (devloadUrl) {
|
||||
browser.loadURL(devloadUrl + '#' + hash).then(_ => {
|
||||
|
||||
})
|
||||
browser.loadURL(devloadUrl + '#' + hash).then(_ => { }).catch(_ => { })
|
||||
} else {
|
||||
browser.loadFile('./public/index.html', {
|
||||
hash
|
||||
}).then(_ => {
|
||||
|
||||
})
|
||||
}).then(_ => { }).catch(_ => { })
|
||||
}
|
||||
}
|
||||
if (args.name) {
|
||||
const er = subWindow.find(item => item.browser == browser);
|
||||
const er = childWindow.find(item => item.browser == browser);
|
||||
if (er) {
|
||||
er.name = args.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建内置浏览器
|
||||
* @param args {url, ?}
|
||||
*/
|
||||
function createWebTabWindow(args) {
|
||||
if (!args) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!utils.isJson(args)) {
|
||||
args = {url: args}
|
||||
}
|
||||
|
||||
if (!allowedUrls.test(args.url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建父级窗口
|
||||
if (!webTabWindow) {
|
||||
let config = Object.assign(args.config || {}, userConf.get('webTabWindow', {}));
|
||||
let webPreferences = args.webPreferences || {};
|
||||
const titleBarOverlay = {
|
||||
height: webTabHeight
|
||||
}
|
||||
if (nativeTheme.shouldUseDarkColors) {
|
||||
titleBarOverlay.color = '#3B3B3D'
|
||||
titleBarOverlay.symbolColor = '#C5C5C5'
|
||||
}
|
||||
webTabWindow = new BrowserWindow(Object.assign({
|
||||
x: mainWindow.getBounds().x + webTabHeight,
|
||||
y: mainWindow.getBounds().y + webTabHeight,
|
||||
width: 1280,
|
||||
height: 800,
|
||||
minWidth: 360,
|
||||
minHeight: 360,
|
||||
center: true,
|
||||
show: false,
|
||||
autoHideMenuBar: true,
|
||||
titleBarStyle: 'hidden',
|
||||
titleBarOverlay,
|
||||
webPreferences: Object.assign({
|
||||
preload: path.join(__dirname, 'electron-preload.js'),
|
||||
webSecurity: true,
|
||||
nodeIntegration: true,
|
||||
contextIsolation: true,
|
||||
nativeWindowOpen: true
|
||||
}, webPreferences),
|
||||
}, config))
|
||||
|
||||
if (nativeTheme.shouldUseDarkColors) {
|
||||
webTabWindow.setBackgroundColor('#3B3B3D')
|
||||
} else {
|
||||
webTabWindow.setBackgroundColor('#EFF0F4')
|
||||
}
|
||||
|
||||
webTabWindow.on('resize', () => {
|
||||
resizeWebTab(0)
|
||||
})
|
||||
|
||||
webTabWindow.on('enter-full-screen', () => {
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'enter-full-screen',
|
||||
}).then(_ => { })
|
||||
})
|
||||
|
||||
webTabWindow.on('leave-full-screen', () => {
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'leave-full-screen',
|
||||
}).then(_ => { })
|
||||
})
|
||||
|
||||
webTabWindow.on('close', event => {
|
||||
if (!willQuitApp) {
|
||||
closeWebTab(0)
|
||||
event.preventDefault()
|
||||
} else {
|
||||
userConf.set('webTabWindow', webTabWindow.getBounds())
|
||||
}
|
||||
})
|
||||
|
||||
webTabWindow.on('closed', () => {
|
||||
webTabView.forEach(({view}) => {
|
||||
try {
|
||||
view.webContents.close()
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
})
|
||||
webTabView = []
|
||||
webTabWindow = null
|
||||
})
|
||||
|
||||
webTabWindow.once('ready-to-show', () => {
|
||||
onShowWindow(webTabWindow);
|
||||
})
|
||||
|
||||
webTabWindow.webContents.once('dom-ready', () => {
|
||||
onShowWindow(webTabWindow);
|
||||
})
|
||||
|
||||
webTabWindow.webContents.on('before-input-event', (event, input) => {
|
||||
if (utils.isMetaOrControl(input) && input.key.toLowerCase() === 'r') {
|
||||
reloadWebTab(0)
|
||||
event.preventDefault()
|
||||
} else if (utils.isMetaOrControl(input) && input.shift && input.key.toLowerCase() === 'i') {
|
||||
devToolsWebTab(0)
|
||||
}
|
||||
})
|
||||
|
||||
webTabWindow.loadFile('./render/tabs/index.html', {}).then(_ => {
|
||||
|
||||
})
|
||||
}
|
||||
if (webTabWindow.isMinimized()) {
|
||||
webTabWindow.restore()
|
||||
}
|
||||
webTabWindow.focus();
|
||||
webTabWindow.show();
|
||||
|
||||
// 创建子窗口
|
||||
const browserView = new BrowserView({
|
||||
useHTMLTitleAndIcon: true,
|
||||
useLoadingView: true,
|
||||
useErrorView: true,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'electron-preload.js'),
|
||||
}
|
||||
})
|
||||
if (nativeTheme.shouldUseDarkColors) {
|
||||
browserView.setBackgroundColor('#575757')
|
||||
} else {
|
||||
browserView.setBackgroundColor('#FFFFFF')
|
||||
}
|
||||
browserView.setBounds({
|
||||
x: 0,
|
||||
y: webTabHeight,
|
||||
width: webTabWindow.getContentBounds().width || 1280,
|
||||
height: (webTabWindow.getContentBounds().height || 800) - webTabHeight,
|
||||
})
|
||||
browserView.webContents.on('destroyed', () => {
|
||||
closeWebTab(browserView.webContents.id)
|
||||
})
|
||||
browserView.webContents.setWindowOpenHandler(({url}) => {
|
||||
if (allowedCalls.test(url)) {
|
||||
return {action: 'allow'}
|
||||
}
|
||||
createWebTabWindow({url})
|
||||
return {action: 'deny'}
|
||||
})
|
||||
browserView.webContents.on('page-title-updated', (event, title) => {
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'title',
|
||||
id: browserView.webContents.id,
|
||||
title: title,
|
||||
url: browserView.webContents.getURL(),
|
||||
}).then(_ => { })
|
||||
})
|
||||
browserView.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL, isMainFrame) => {
|
||||
if (!errorDescription) {
|
||||
return
|
||||
}
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'title',
|
||||
id: browserView.webContents.id,
|
||||
title: errorDescription,
|
||||
url: browserView.webContents.getURL(),
|
||||
}).then(_ => { })
|
||||
})
|
||||
browserView.webContents.on('page-favicon-updated', (event, favicons) => {
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'favicon',
|
||||
id: browserView.webContents.id,
|
||||
favicons
|
||||
}).then(_ => { })
|
||||
})
|
||||
browserView.webContents.on('did-start-loading', _ => {
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'start-loading',
|
||||
id: browserView.webContents.id,
|
||||
}).then(_ => { })
|
||||
})
|
||||
browserView.webContents.on('did-stop-loading', _ => {
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'stop-loading',
|
||||
id: browserView.webContents.id,
|
||||
}).then(_ => { })
|
||||
// 加载完成暗黑模式下把窗口背景色改成白色,避免透明网站背景色穿透
|
||||
if (nativeTheme.shouldUseDarkColors) {
|
||||
browserView.setBackgroundColor('#FFFFFF')
|
||||
}
|
||||
})
|
||||
browserView.webContents.on('before-input-event', (event, input) => {
|
||||
if (utils.isMetaOrControl(input) && input.key.toLowerCase() === 'r') {
|
||||
browserView.webContents.reload()
|
||||
event.preventDefault()
|
||||
} else if (utils.isMetaOrControl(input) && input.shift && input.key.toLowerCase() === 'i') {
|
||||
browserView.webContents.toggleDevTools()
|
||||
}
|
||||
})
|
||||
browserView.webContents.loadURL(args.url).then(_ => { }).catch(_ => { })
|
||||
|
||||
webTabWindow.addBrowserView(browserView)
|
||||
webTabView.push({
|
||||
id: browserView.webContents.id,
|
||||
view: browserView
|
||||
})
|
||||
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'create',
|
||||
id: browserView.webContents.id,
|
||||
url: args.url,
|
||||
}).then(_ => { })
|
||||
activateWebTab(browserView.webContents.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前内置浏览器标签
|
||||
* @returns {Electron.BrowserView|undefined}
|
||||
*/
|
||||
function currentWebTab() {
|
||||
const views = webTabWindow.getBrowserViews()
|
||||
const view = views.length ? views[views.length - 1] : undefined
|
||||
if (!view) {
|
||||
return undefined
|
||||
}
|
||||
return webTabView.find(item => item.id == view.webContents.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新加载内置浏览器标签
|
||||
* @param id
|
||||
*/
|
||||
function reloadWebTab(id) {
|
||||
const item = id === 0 ? currentWebTab() : webTabView.find(item => item.id == id)
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
item.view.webContents.reload()
|
||||
}
|
||||
|
||||
/**
|
||||
* 内置浏览器标签打开开发者工具
|
||||
* @param id
|
||||
*/
|
||||
function devToolsWebTab(id) {
|
||||
const item = id === 0 ? currentWebTab() : webTabView.find(item => item.id == id)
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
item.view.webContents.toggleDevTools()
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整内置浏览器标签尺寸
|
||||
* @param id
|
||||
*/
|
||||
function resizeWebTab(id) {
|
||||
const item = id === 0 ? currentWebTab() : webTabView.find(item => item.id == id)
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
item.view.setBounds({
|
||||
x: 0,
|
||||
y: webTabHeight,
|
||||
width: webTabWindow.getContentBounds().width || 1280,
|
||||
height: (webTabWindow.getContentBounds().height || 800) - webTabHeight,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换内置浏览器标签
|
||||
* @param id
|
||||
*/
|
||||
function activateWebTab(id) {
|
||||
const item = id === 0 ? currentWebTab() : webTabView.find(item => item.id == id)
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
resizeWebTab(item.id)
|
||||
webTabWindow.setTopBrowserView(item.view)
|
||||
item.view.webContents.focus()
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'switch',
|
||||
id: item.id,
|
||||
}).then(_ => { })
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭内置浏览器标签
|
||||
* @param id
|
||||
*/
|
||||
function closeWebTab(id) {
|
||||
const item = id === 0 ? currentWebTab() : webTabView.find(item => item.id == id)
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
if (webTabView.length === 1) {
|
||||
webTabWindow.hide()
|
||||
}
|
||||
webTabWindow.removeBrowserView(item.view)
|
||||
try {
|
||||
item.view.webContents.close()
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
|
||||
const index = webTabView.findIndex(({id}) => item.id == id)
|
||||
if (index > -1) {
|
||||
webTabView.splice(index, 1)
|
||||
}
|
||||
|
||||
utils.onDispatchEvent(webTabWindow.webContents, {
|
||||
event: 'close',
|
||||
id: item.id,
|
||||
}).then(_ => { })
|
||||
|
||||
if (webTabView.length === 0) {
|
||||
userConf.set('webTabWindow', webTabWindow.getBounds())
|
||||
webTabWindow.destroy()
|
||||
} else {
|
||||
activateWebTab(0)
|
||||
}
|
||||
}
|
||||
|
||||
const getTheLock = app.requestSingleInstanceLock()
|
||||
if (!getTheLock) {
|
||||
app.quit()
|
||||
@@ -329,8 +686,8 @@ ipcMain.on('windowQuit', (event) => {
|
||||
* 创建路由窗口
|
||||
* @param args {path, ?}
|
||||
*/
|
||||
ipcMain.on('windowRouter', (event, args) => {
|
||||
createSubWindow(args)
|
||||
ipcMain.on('openChildWindow', (event, args) => {
|
||||
createChildWindow(args)
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
@@ -338,9 +695,89 @@ ipcMain.on('windowRouter', (event, args) => {
|
||||
* 更新路由窗口
|
||||
* @param args {?name, ?path} // name: 不是要更改的窗口名,是要把窗口名改成什么, path: 地址
|
||||
*/
|
||||
ipcMain.on('updateChildWindow', (event, args) => {
|
||||
const browser = BrowserWindow.fromWebContents(event.sender);
|
||||
updateChildWindow(browser, args)
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
/**
|
||||
* 创建路由窗口(todo 已废弃)
|
||||
* @param args {path, ?}
|
||||
*/
|
||||
ipcMain.on('windowRouter', (event, args) => {
|
||||
createChildWindow(args)
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
/**
|
||||
* 更新路由窗口(todo 已废弃)
|
||||
* @param args {?name, ?path} // name: 不是要更改的窗口名,是要把窗口名改成什么, path: 地址
|
||||
*/
|
||||
ipcMain.on('updateRouter', (event, args) => {
|
||||
const browser = BrowserWindow.fromWebContents(event.sender);
|
||||
updateSubWindow(browser, args)
|
||||
updateChildWindow(browser, args)
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
/**
|
||||
* 内置浏览器 - 打开创建
|
||||
* @param args {url, ?}
|
||||
*/
|
||||
ipcMain.on('openWebTabWindow', (event, args) => {
|
||||
createWebTabWindow(args)
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
/**
|
||||
* 内置浏览器 - 激活标签
|
||||
* @param id
|
||||
*/
|
||||
ipcMain.on('webTabActivate', (event, id) => {
|
||||
activateWebTab(id)
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
/**
|
||||
* 内置浏览器 - 关闭标签
|
||||
* @param id
|
||||
*/
|
||||
ipcMain.on('webTabClose', (event, id) => {
|
||||
closeWebTab(id)
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
/**
|
||||
* 内置浏览器 - 在外部浏览器打开
|
||||
*/
|
||||
ipcMain.on('webTabExternal', (event) => {
|
||||
const item = currentWebTab()
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
openExternal(item.view.webContents.getURL())
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
/**
|
||||
* 内置浏览器 - 打开开发者工具
|
||||
*/
|
||||
ipcMain.on('webTabOpenDevTools', (event) => {
|
||||
const item = currentWebTab()
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
item.view.webContents.openDevTools()
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
/**
|
||||
* 内置浏览器 - 销毁所有标签及窗口
|
||||
*/
|
||||
ipcMain.on('webTabDestroyAll', (event) => {
|
||||
if (webTabWindow) {
|
||||
webTabWindow.destroy()
|
||||
}
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
@@ -377,8 +814,8 @@ ipcMain.on('windowDestroy', (event) => {
|
||||
/**
|
||||
* 关闭所有子窗口
|
||||
*/
|
||||
ipcMain.on('subWindowCloseAll', (event) => {
|
||||
subWindow.some(({browser}) => {
|
||||
ipcMain.on('childWindowCloseAll', (event) => {
|
||||
childWindow.some(({browser}) => {
|
||||
browser && browser.close()
|
||||
})
|
||||
event.returnValue = "ok"
|
||||
@@ -387,8 +824,8 @@ ipcMain.on('subWindowCloseAll', (event) => {
|
||||
/**
|
||||
* 销毁所有子窗口
|
||||
*/
|
||||
ipcMain.on('subWindowDestroyAll', (event) => {
|
||||
subWindow.some(({browser}) => {
|
||||
ipcMain.on('childWindowDestroyAll', (event) => {
|
||||
childWindow.some(({browser}) => {
|
||||
browser && browser.destroy()
|
||||
})
|
||||
event.returnValue = "ok"
|
||||
@@ -644,6 +1081,9 @@ ipcMain.on('updateCheckAndDownload', (event, args) => {
|
||||
autoUpdater.setFeedURL(args)
|
||||
}
|
||||
autoUpdater.checkForUpdates().then(info => {
|
||||
if (!info) {
|
||||
return
|
||||
}
|
||||
if (utils.compareVersion(config.version, info.updateInfo.version) >= 0) {
|
||||
return
|
||||
}
|
||||
@@ -685,7 +1125,7 @@ ipcMain.on('mainWindowActive', (event) => {
|
||||
ipcMain.on('updateQuitAndInstall', (event) => {
|
||||
event.returnValue = "ok"
|
||||
willQuitApp = true
|
||||
subWindow.some(({browser}) => {
|
||||
childWindow.some(({browser}) => {
|
||||
browser && browser.destroy()
|
||||
})
|
||||
setTimeout(_ => {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user