Compare commits
553 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76664c61c4 | ||
|
|
24839f960f | ||
|
|
ce7d3f8475 | ||
|
|
5e8a6af74c | ||
|
|
23a363aeea | ||
|
|
6cbf2bbada | ||
|
|
ee9cf0a6b6 | ||
|
|
8d39b4aa0d | ||
|
|
3c93ad18b2 | ||
|
|
cc125cc292 | ||
|
|
6823d87198 | ||
|
|
288e857321 | ||
|
|
73d1950d97 | ||
|
|
ee2b047e5d | ||
|
|
ae83fce524 | ||
|
|
985c5ff54b | ||
|
|
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 | ||
|
|
e215cda700 | ||
|
|
846fdcf145 | ||
|
|
ecdabc668d | ||
|
|
e8839974d4 | ||
|
|
2a864b6617 | ||
|
|
ada88a1c02 | ||
|
|
8fe16416f9 | ||
|
|
0daf06c06d | ||
|
|
3b697e7400 | ||
|
|
a543f8716b | ||
|
|
63703a029f | ||
|
|
22415e6c61 | ||
|
|
1a69e76fe7 | ||
|
|
7f916c4770 | ||
|
|
f76d36a74b | ||
|
|
ab0539a263 | ||
|
|
4104dea68e | ||
|
|
5aded9daa3 | ||
|
|
91d5bd80ff | ||
|
|
40d56a0155 | ||
|
|
54117fe51a | ||
|
|
fbd662e400 | ||
|
|
ccb31a81f8 | ||
|
|
dbb9366de6 | ||
|
|
6d7a4edae3 | ||
|
|
632068a74c | ||
|
|
4e78920f99 | ||
|
|
fdc85bbcbf | ||
|
|
67dafae9d6 | ||
|
|
989e5a5f9d | ||
|
|
a7e5bd0b80 | ||
|
|
da131746be | ||
|
|
8a7e80fe86 | ||
|
|
865dc61cd1 | ||
|
|
c8b96a8bce | ||
|
|
5546dbaa0e | ||
|
|
fd6312408b | ||
|
|
4f4c6de8a2 | ||
|
|
4506ba8cd3 | ||
|
|
9300e9fd9a | ||
|
|
a4eb8317da | ||
|
|
0e819de1bc | ||
|
|
9800f9e3da | ||
|
|
a0f6a17005 | ||
|
|
6087c7fed0 | ||
|
|
3fa0b472d2 | ||
|
|
1ce96ddae6 | ||
|
|
d4ef140c8e | ||
|
|
7de575e236 | ||
|
|
f0f0883a88 | ||
|
|
c1695a78d6 | ||
|
|
15e37eded3 | ||
|
|
57cd91e6d4 | ||
|
|
a178334d8e | ||
|
|
dd8ba7e8da | ||
|
|
d26df91960 | ||
|
|
f249763d41 | ||
|
|
1bada9ab30 | ||
|
|
a185ab2973 | ||
|
|
ce83bef0ed | ||
|
|
66135d8222 | ||
|
|
e99e069e55 | ||
|
|
327cdbc873 | ||
|
|
6eabba9679 | ||
|
|
c99f6cfcf2 | ||
|
|
0579a73c1c | ||
|
|
12b3c14299 | ||
|
|
c21da4292b | ||
|
|
3f9cdfd887 | ||
|
|
8dac2bc444 | ||
|
|
13ec6ec323 | ||
|
|
59aa854470 | ||
|
|
e0c3ea4456 | ||
|
|
d6a3727713 | ||
|
|
48cd32742c | ||
|
|
852ceba828 | ||
|
|
905c8be6eb | ||
|
|
fad98dcc9d | ||
|
|
8b5409de5a | ||
|
|
bcf1ad0870 | ||
|
|
617e88e0b5 | ||
|
|
c9e0840173 | ||
|
|
5e4f99da6c | ||
|
|
28bc303fcf | ||
|
|
91c63f281b | ||
|
|
7b3769b1db | ||
|
|
211f9f0c15 | ||
|
|
37ccf4dacb | ||
|
|
971167cad3 | ||
|
|
332bed3136 | ||
|
|
e2a9906de0 | ||
|
|
c5879e4376 | ||
|
|
22324f4c16 | ||
|
|
fa9c3b4f2f | ||
|
|
f411f17386 | ||
|
|
ab3a82300c | ||
|
|
dbb9162267 | ||
|
|
84d3e4f617 | ||
|
|
6209b53321 | ||
|
|
62a2bcf71d | ||
|
|
cdefe9d4a7 | ||
|
|
2bebad1112 | ||
|
|
9f186f1e9c | ||
|
|
a6873302f3 | ||
|
|
615f40d458 | ||
|
|
c4b49b34b8 | ||
|
|
d12fb47902 | ||
|
|
21132f475a | ||
|
|
a55e0a457d | ||
|
|
fa7b049316 | ||
|
|
f8f5bc476b | ||
|
|
e5c622cb89 | ||
|
|
aa70c41041 | ||
|
|
3cce9b67d4 | ||
|
|
c0342ea6d1 | ||
|
|
2813f4c062 | ||
|
|
9ca9de0d7e | ||
|
|
603db9de7f | ||
|
|
c4e72507e0 | ||
|
|
d06d1c177c | ||
|
|
4ff1cf68fc | ||
|
|
8d92933e43 | ||
|
|
9497fb1bb6 | ||
|
|
fc65d56977 | ||
|
|
fe4cba61e2 | ||
|
|
8144bea613 | ||
|
|
7a431d86d2 | ||
|
|
7ecfd86ffa | ||
|
|
66b9e7e9b3 | ||
|
|
6bed109f97 | ||
|
|
fbc5eed5c5 | ||
|
|
43b665652e | ||
|
|
5760d3ef0f | ||
|
|
e712b99287 | ||
|
|
85d88b6800 | ||
|
|
1a62a47935 | ||
|
|
689d842d58 | ||
|
|
8215e73a95 | ||
|
|
d3fc274f08 | ||
|
|
e4bcb8b518 | ||
|
|
9a942c483d | ||
|
|
e9fd223808 | ||
|
|
5dfc66fc21 | ||
|
|
bab82dc290 | ||
|
|
4c1125b9e1 | ||
|
|
85ef2d9687 | ||
|
|
b7fc815d58 | ||
|
|
ad1cc964c9 | ||
|
|
96a2b250a3 | ||
|
|
d72ab58f98 | ||
|
|
abd453f2f6 | ||
|
|
4b7283dbe8 | ||
|
|
f5a068fffc | ||
|
|
faf5dec08a | ||
|
|
e4070e249d | ||
|
|
fe5ec9677a | ||
|
|
5fdd5adef8 | ||
|
|
bc250ad4b8 | ||
|
|
22050b7488 | ||
|
|
6df906aa24 | ||
|
|
d2f20128bb | ||
|
|
cef19488d2 | ||
|
|
0ceb2de79d | ||
|
|
79feaaf801 | ||
|
|
34c005001d | ||
|
|
3508d7a472 | ||
|
|
1e58587b1c | ||
|
|
e99f952c28 | ||
|
|
b0742021b6 | ||
|
|
5e784f64a6 | ||
|
|
32aae08ef2 | ||
|
|
af46fc501b | ||
|
|
07c3a958fa | ||
|
|
ecdbf8765f | ||
|
|
5682943c24 | ||
|
|
5fbc5d3164 | ||
|
|
90af11a842 | ||
|
|
b644a65f22 | ||
|
|
6db82c8176 | ||
|
|
fa149fcaa9 | ||
|
|
9772e4b48a | ||
|
|
08cc4a4815 | ||
|
|
aa554627fb | ||
|
|
420e1a9d63 | ||
|
|
b8ed8566ee | ||
|
|
bbb3cee927 | ||
|
|
2737fa4697 | ||
|
|
14913ae312 | ||
|
|
d2fe6217a6 | ||
|
|
aef46d4c76 | ||
|
|
ad494b86e3 | ||
|
|
c0a594655d | ||
|
|
ed4afa63f0 | ||
|
|
08fccf4adc | ||
|
|
a52e9e152d | ||
|
|
38befc94ca | ||
|
|
df4c8cc352 | ||
|
|
2305d30d35 | ||
|
|
cdc7e671ce | ||
|
|
d541397594 | ||
|
|
4205b68b8c | ||
|
|
6ffb458ffc | ||
|
|
e43dd53e4f | ||
|
|
5ef4516e3d | ||
|
|
51b1d78d8a | ||
|
|
3fdcbf92b6 | ||
|
|
742875d5eb | ||
|
|
4a79eeb9df | ||
|
|
43cee0eb4a | ||
|
|
92beb20455 | ||
|
|
930f55b080 | ||
|
|
e7239b3c5c | ||
|
|
1e92ca5518 | ||
|
|
c9e3e88443 | ||
|
|
05f20eb761 | ||
|
|
a9033c610b | ||
|
|
e9e1cd9028 | ||
|
|
4e8239377f | ||
|
|
83a501b69f | ||
|
|
efe80ce0eb | ||
|
|
e0fc1c5ef7 | ||
|
|
a38ddf83f2 | ||
|
|
e7fbe8bb49 | ||
|
|
523166da48 | ||
|
|
a24990e06a | ||
|
|
3f11451f3c | ||
|
|
0b888b9597 | ||
|
|
acddde8faa | ||
|
|
c587a50505 | ||
|
|
7befd4277e | ||
|
|
bbc29d5d5f | ||
|
|
9dc7c08b61 | ||
|
|
0f690a99df | ||
|
|
d8c8cca6fc | ||
|
|
9bccc99228 | ||
|
|
4f1016a939 | ||
|
|
71fb50b4ce | ||
|
|
7359b04001 | ||
|
|
5700b97e98 | ||
|
|
19e50be276 | ||
|
|
14595d3a60 | ||
|
|
eea9d1f3ce | ||
|
|
157147ded7 | ||
|
|
b8d51c6462 | ||
|
|
7fe3436819 | ||
|
|
a2cd57641b | ||
|
|
80bfc2c86f | ||
|
|
e3bd895908 | ||
|
|
018ff205f5 | ||
|
|
9fee5c61a6 | ||
|
|
ba8e7b3fbb | ||
|
|
dbe53481f1 | ||
|
|
8b9cfbcf29 | ||
|
|
db67d662d1 | ||
|
|
dcf947c498 | ||
|
|
c94025013b | ||
|
|
304b22b1c1 | ||
|
|
f23ece5e9e | ||
|
|
651194f12e | ||
|
|
ae00f49b30 | ||
|
|
60f5341a9a | ||
|
|
3b17ebcb09 | ||
|
|
c861f49e29 | ||
|
|
1d2f50c896 | ||
|
|
4f676c0ccb | ||
|
|
5801d0fc14 | ||
|
|
525ac41258 | ||
|
|
39a0d001ef | ||
|
|
0e9c1c19ce | ||
|
|
0011e04823 | ||
|
|
e919170ee8 | ||
|
|
8024edc1b0 | ||
|
|
984c68dc09 | ||
|
|
c35a177ac1 | ||
|
|
ea82e2dbfe | ||
|
|
034bd7dcb8 | ||
|
|
343905362c | ||
|
|
79d5b70364 |
@@ -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,8 @@ on:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
Build:
|
||||
name: Build Mac
|
||||
runs-on: macos-latest
|
||||
environment: build
|
||||
|
||||
@@ -15,10 +16,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 +30,6 @@ jobs:
|
||||
DP_KEY: ${{ secrets.DP_KEY }}
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
GH_REPOSITORY: ${{ github.repository }}
|
||||
run: ./cmd electron all
|
||||
run: |
|
||||
./cmd electron mac
|
||||
|
||||
31
.github/workflows/publish-desktop-win.yml
vendored
Normal file
31
.github/workflows/publish-desktop-win.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: Publish Win
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
Build:
|
||||
name: Build Windows
|
||||
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
|
||||
648
CHANGELOG.md
648
CHANGELOG.md
@@ -2,7 +2,640 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [0.31.13]
|
||||
## [0.36.78]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 解决 Unable to preventDefault inside passive event listener 报错
|
||||
- 截图粘贴出现两张图的情况
|
||||
- 聊天输入中文过程跟placeholder内容叠加的问题
|
||||
|
||||
## [0.36.75]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Added non-passive event listener to a scroll-blocking 'touchstart' event
|
||||
|
||||
### Performance
|
||||
|
||||
- 下载pdf使用自带浏览器
|
||||
- 优化消息加载中效果
|
||||
- 审批内容禁止转发
|
||||
- 滑动快捷表情选择
|
||||
- 优化聊天输入框
|
||||
- Update chat editor
|
||||
- 优化机器人回复
|
||||
- 优化android体验
|
||||
|
||||
## [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
|
||||
|
||||
- 修复置顶人员
|
||||
- 修复高危bug
|
||||
- 1.修复可见效数据取值,2.修复设置可见效指定人员不成功
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化打包下载
|
||||
- 去掉无用引用
|
||||
- 优化报告未读接口
|
||||
- 优化图片显示
|
||||
- 优化代码
|
||||
- 代码整理
|
||||
- 优化待审批流程数量接口
|
||||
- 代码优化
|
||||
- 优化未读消息提示
|
||||
- 优化预览消息
|
||||
- 优化缓存数据
|
||||
- 任务可见性用户 - 分表优化
|
||||
- 代码命名优化
|
||||
- 移动任务后,对应项目路径也要更改显示
|
||||
- 升级okr容器
|
||||
- 导出任务统计 - 下载地址换成按钮
|
||||
|
||||
## [0.33.58]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 修复已知问题
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化会话列表
|
||||
|
||||
## [0.33.54]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 撤回消息不删除消息的情况
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化录音load效果
|
||||
- 优化消息列表
|
||||
- 优化应用图标
|
||||
- 升级okr容器
|
||||
- 优化用户选择器
|
||||
- 优化对话列表接口数据
|
||||
- 优化未读消息提示动画
|
||||
- 优化消息更新机制
|
||||
- 优化缓存
|
||||
|
||||
## [0.33.41]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 更新导致的小问题
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化任务修改
|
||||
|
||||
## [0.33.34]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 版本验证有问题,先干掉
|
||||
- Android 无法回删输入框内的@(mention)内容
|
||||
- Android 长按重复事件
|
||||
- 合并修复
|
||||
|
||||
### Features
|
||||
|
||||
- 消息置顶功能 - 50%
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化发送消息时闪现2条一样的情况
|
||||
- 优化消息首页加载效果
|
||||
- 优化Android长按事件
|
||||
- 优化输入框自动高度
|
||||
- 点击消息页面会发生跳动的问题
|
||||
- 优化待办列表
|
||||
- 调整任务过多提示范围
|
||||
- 优化消息阅读规则
|
||||
- Okr版本升级
|
||||
- 1.数据库迁移文件修复 2.转发样式优化
|
||||
- 兼容okr1.1版本
|
||||
- 整体数据库索引和字段类型优化
|
||||
- 项目列表数据库查询优化
|
||||
|
||||
## [0.32.65]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 修复头像出现D的情况
|
||||
|
||||
### Documentation
|
||||
|
||||
- 更新文档
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化任务列表查询速度
|
||||
- 优化消息输入框内选择文本
|
||||
- 移动端修改任务详情确认提示
|
||||
- 优化发送录音消息抖动
|
||||
- 优化录音效果
|
||||
- 优化快捷键设置
|
||||
|
||||
## [0.32.55]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 聊天输入框内容为空时仍可以长安发送显示发送菜单
|
||||
- 文件页移动端滑动返回失败情况
|
||||
- 会员头像显示错乱
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化输入空换行时的兼容问题
|
||||
- 优化设置页面
|
||||
- 优化应用中心菜单排序
|
||||
- 更新录音插件
|
||||
- 更换移动任务图标
|
||||
- 优化设置返回跟滑动返回冲突
|
||||
- 优化键盘设置
|
||||
- 优化清除缓存数据
|
||||
- 优化阅读消息列表机制
|
||||
- 优化项目页面任务加载速度
|
||||
- 代码优化
|
||||
|
||||
## [0.32.35]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 修复重复SSE请求的问题
|
||||
- 部分pad设备横版和竖屏反过来
|
||||
- 用户选择组件,单选时不需要显示项目
|
||||
- 文件主题修复
|
||||
- 修复客户端版本更新按钮的显示问题
|
||||
- 标注取值bug修复
|
||||
- 项目权限 - 100%
|
||||
- 修复安装项目报错
|
||||
|
||||
### Features
|
||||
|
||||
- 新增以下为新消息提示
|
||||
- Okr结果分析 - 部门负责人也可以看
|
||||
- Okr1.1 兼容开发
|
||||
- 未读消息优化
|
||||
- 翻译
|
||||
- 添加投票功能 - 100%
|
||||
- 样式调优
|
||||
- 添加投票功能 30%
|
||||
- 接龙功能 - 100%
|
||||
- 添加接龙
|
||||
- 1.任务移动功能优化,2.导航样式优化
|
||||
- 新增压缩下载完成后系统机器人提醒
|
||||
- 添加一个 @我的 消息标签
|
||||
- 转发消息 - 添加单选模式
|
||||
- 转发消息 - 添加来源显示
|
||||
- 首页改版 - 100%
|
||||
- 新增项目任务创建权限功能 - 90%
|
||||
- 更换calendar
|
||||
- 首页改版
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化消息阅读逻辑
|
||||
- 微应用优化
|
||||
- 优化未读消息机制
|
||||
- 优化重连时消息列表跳回第一页的情况
|
||||
- 优化消息更新太快导致不更新数据的情况
|
||||
- 机器人添加清空上下文菜单
|
||||
- 优化翻译
|
||||
- 发送消息失败时再次编辑改为重新发送
|
||||
- 优化通过消息设置待办功能
|
||||
- 优化扫一扫登录功能
|
||||
- 优化头像
|
||||
- 兼容okr1.1版本
|
||||
- 接龙和投票的样式优化
|
||||
- 逻辑强化
|
||||
- 搜索消息时按esc取消搜索
|
||||
- 接龙优化
|
||||
- 移动设备优化消息输入框菜单
|
||||
- 优化消息输入框@所有人暗黑样式
|
||||
- 优化@人名换行的情况
|
||||
- 样式优化
|
||||
- 优化导出任务统计
|
||||
- 客户端下载按钮,仪表盘不显示
|
||||
- 细节优化
|
||||
|
||||
## [0.32.17]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 修复打包下载问题
|
||||
- 1. 修复 windows端 右键发送 是直接发送了,没有出现使用md格式发送 2.其他bug修复
|
||||
- 修复统一打包下载命名
|
||||
|
||||
### Features
|
||||
|
||||
- 添加项目权限功能 - 30%
|
||||
|
||||
### Performance
|
||||
|
||||
- 审批版本更新
|
||||
- Okr 和 审批中心弄一些演示数据
|
||||
- 项目邀请页 - 安卓用opne方式打开
|
||||
|
||||
## [0.32.9]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 移动打开分享链接时先关闭聊天窗口
|
||||
- 修复未登录时,进入邀请项目的链接会弹出多次登录框的情况
|
||||
- 修复进度完成后再次完成
|
||||
- 华为手机弹出键盘时出现空白区域的问题
|
||||
- 修复错误提示
|
||||
- 栏目被删除的时候,已归档任务不受影响
|
||||
- 直接拖文件会发送两次的bug修复
|
||||
|
||||
### Features
|
||||
|
||||
- 邀请加入项目的链接客户端直接打开
|
||||
- 新增临时压缩下载文件24小时自动清理
|
||||
- 任务加时功能 (模仿可见性的交互,任务延期和修改时间) - 100%
|
||||
- 任务加时功能 (模仿可见性的交互,任务延期和修改时间) - 70%
|
||||
- 添加功能 - 每天发出本项目未领取任务
|
||||
- 添加转移任务到别的项目功能
|
||||
- 键盘设置里面,支持设置回车发送还是按键发送
|
||||
- 上传文件大小限制
|
||||
- 任务标题有换行时聊天引用会失败
|
||||
- 文件共享只读禁止下载文件
|
||||
- 保存任务详情至文件的方法 添加失败日志
|
||||
- 翻译
|
||||
- 新增实现文件夹下载以及多文件压缩下载功能
|
||||
- 任务可以筛选未设置时间的
|
||||
- 临时账号可以主动跟机器人聊天
|
||||
|
||||
### Performance
|
||||
|
||||
- Office只读模式,隐藏下载按钮
|
||||
- 优化实现文件夹下载以及多文件压缩下载功能
|
||||
- 机器人设置页面,点点点看不到内容,需要给弹窗看详细内容
|
||||
- 文件选中后,移动端页面宽度放不下对应内容
|
||||
- 文件选中后,移动端页面宽度放不下对应内容,没有滚动条
|
||||
- 压缩下载改名打包下载
|
||||
- 复制链接去除主题语言参数
|
||||
|
||||
## [0.31.75]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 思维导图缩放后无法触发手指移动
|
||||
|
||||
### Performance
|
||||
|
||||
- 新增文心一言模型
|
||||
- 补充优化
|
||||
- Update documentserver
|
||||
- Openid supports gpt-4 model
|
||||
|
||||
## [0.31.65]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 手机下载文件名出现html的情况
|
||||
- 桌面客户端内聊天复制图片模糊的情况
|
||||
- 桌面客户端截图功能
|
||||
|
||||
### Performance
|
||||
|
||||
- 标记已读/未读等待效果
|
||||
- App内转发没有等待效果
|
||||
|
||||
## [0.31.54]
|
||||
|
||||
### Performance
|
||||
|
||||
- 优化审批信息推送内容(时间、事由)
|
||||
|
||||
## [0.31.37]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Ai return error
|
||||
- 修复审批数据导出时间以请假时间为准
|
||||
- 修复服务价格页面文字
|
||||
|
||||
### Features
|
||||
|
||||
- 新增用户审批状态显示
|
||||
- 1 新增用户审批状态接口 2 新增审批用户查询条件
|
||||
|
||||
## [0.31.5]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -97,14 +730,12 @@ All notable changes to this project will be documented in this file.
|
||||
- 去掉test信息
|
||||
- 按照dootask启动原始尺寸截取使用说明的图
|
||||
- 修改边栏目录滚动效果
|
||||
- 修改边栏目录滚动效果
|
||||
- 官网使用说明的图重新截取更换
|
||||
- 优化官网布局与样式
|
||||
- 修复下载英文页面跳转
|
||||
|
||||
### Features
|
||||
|
||||
- 新增创建聊天关联id
|
||||
- 新增创建聊天关联id
|
||||
- Okr信息面板新增"打开OKR"按钮
|
||||
- 新增OKR信息推送
|
||||
@@ -191,7 +822,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 优化会员选择器
|
||||
- 优化图片压缩
|
||||
- 回复图片显示图片搜略图
|
||||
- 优化会员选择器
|
||||
- 会员选择下拉框提示
|
||||
|
||||
## [0.27.26]
|
||||
@@ -222,7 +852,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- 修复获取聊天列表的接口
|
||||
- 添加密码账号长度限制
|
||||
- 添加密码账号长度限制
|
||||
- Dootask对接系统分享 - 添加头像返回
|
||||
- 兼容加密bug问题处理
|
||||
- Dootask对接系统分享
|
||||
@@ -272,7 +901,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- 审批流程静态页
|
||||
- 审批流程静态页
|
||||
|
||||
### Performance
|
||||
@@ -1557,7 +2185,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 优化甘特图
|
||||
- 优化任务列表切换显示
|
||||
- 更新icon图标库
|
||||
- 更新icon图标库
|
||||
- 已删除任务详情任务描述改为只读
|
||||
- 已删除任务操作文案及显示优化
|
||||
- 项目--删除任务查看详情页功能
|
||||
@@ -1648,7 +2275,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 报表导出任务没有流程日志判断优化
|
||||
- 修复登录页设置下拉显示不全的情况
|
||||
- 处理回滚后异常代码
|
||||
- 处理回滚后异常代码
|
||||
- 【系统设置】邮件设置提前小时数双向绑定无效问题修改
|
||||
|
||||
### Features
|
||||
@@ -1736,7 +2362,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 调整消息置顶标识位置
|
||||
- 消息列表详情增加'置顶'标识
|
||||
- 项目列表置顶优化
|
||||
- 项目列表置顶优化
|
||||
- 【文件】剪切后加'取消剪切'按钮
|
||||
- 消息会话右键时隐藏滚动条
|
||||
- 页面高度足够时只滚动项目部分
|
||||
@@ -1837,7 +2462,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 该文件版本已经改变了。该页面将被重新加载
|
||||
- 点击切换语言一级菜单出现的兼容问题
|
||||
- 上传文件夹
|
||||
- 该文件版本已经改变了。该页面将被重新加载
|
||||
- 团队管理新增身份筛选项
|
||||
- 任务文件支持更多格式上传
|
||||
|
||||
@@ -1875,7 +2499,6 @@ All notable changes to this project will be documented in this file.
|
||||
- 任务中没有聊天记录时,发送图片无法成功
|
||||
- 修复消息撤回文字提示在第一条时会被顶部遮住的问题
|
||||
- 修复个人对话为空时无法重复打开该对话的问题
|
||||
- 修复消息撤回文字提示在第一条时会被顶部遮住的问题
|
||||
- MacOS客户端首次不加载角标的问题
|
||||
- 工作流列表接口用作筛选时不用传多余参数
|
||||
|
||||
@@ -1976,7 +2599,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
- 工作报告优化
|
||||
- 规范代码
|
||||
- 工作报告优化
|
||||
- 共享文件删除、移动改为仅限所有者或创建者操作
|
||||
|
||||
## [0.6.38]
|
||||
@@ -2256,7 +2878,6 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
### Performance
|
||||
|
||||
- 客户端新窗口打开文件
|
||||
- 客户端窗口标题
|
||||
- 领取任务流程
|
||||
- 到期时间格式化
|
||||
@@ -2269,7 +2890,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应用
|
||||
|
||||
@@ -1239,7 +1239,7 @@
|
||||
* Call the given Closure / class@method and inject its dependencies.
|
||||
*
|
||||
* @param callable|string $callback
|
||||
* @param \Illuminate\Container\array<string, mixed> $parameters
|
||||
* @param array<string, mixed> $parameters
|
||||
* @param string|null $defaultMethod
|
||||
* @return mixed
|
||||
* @throws \InvalidArgumentException
|
||||
|
||||
@@ -19,6 +19,7 @@ use App\Models\UserDepartment;
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use App\Module\BillMultipleExport;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
|
||||
/**
|
||||
* @apiDefine approve
|
||||
*
|
||||
@@ -27,6 +28,7 @@ use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
class ApproveController extends AbstractController
|
||||
{
|
||||
private $flow_url = '';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->flow_url = env('FLOW_URL') ?: 'http://approve';
|
||||
@@ -71,7 +73,7 @@ class ApproveController extends AbstractController
|
||||
{
|
||||
User::auth();
|
||||
$data['name'] = Request::input('name');
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/procdef/findAll', json_encode($data));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/procdef/findAll', json_encode($data));
|
||||
$procdef = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$procdef || $procdef['status'] != 200 || $ret['ret'] == 0) {
|
||||
// info($ret);
|
||||
@@ -98,7 +100,7 @@ class ApproveController extends AbstractController
|
||||
{
|
||||
User::auth('admin');
|
||||
$data['id'] = Request::input('id');
|
||||
$ret = Ihttp::ihttp_get($this->flow_url.'/api/v1/workflow/procdef/delById?'.http_build_query($data));
|
||||
$ret = Ihttp::ihttp_get($this->flow_url . '/api/v1/workflow/procdef/delById?' . http_build_query($data));
|
||||
$procdef = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$procdef || $procdef['status'] != 200) {
|
||||
return Base::retError($procdef['message'] ?? '删除失败');
|
||||
@@ -131,7 +133,7 @@ class ApproveController extends AbstractController
|
||||
//
|
||||
$var = json_decode(Request::input('var'), true);
|
||||
$data['var'] = $var;
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/process/start', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/process/start', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '启动失败');
|
||||
@@ -193,7 +195,7 @@ class ApproveController extends AbstractController
|
||||
|
||||
$processInst = $this->getProcessById($data['proc_inst_id']);
|
||||
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/process/addGlobalComment', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/process/addGlobalComment', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '添加失败');
|
||||
@@ -201,11 +203,11 @@ class ApproveController extends AbstractController
|
||||
|
||||
// 推送通知
|
||||
$botUser = User::botGetOrCreate('approval-alert');
|
||||
foreach ( $processInst['userids'] as $id) {
|
||||
if($id != $user->userid){
|
||||
foreach ($processInst['userids'] as $id) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -237,7 +239,7 @@ class ApproveController extends AbstractController
|
||||
$data['task_id'] = intval(Request::input('task_id'));
|
||||
$data['pass'] = Request::input('pass');
|
||||
$data['comment'] = Request::input('comment');
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/task/complete', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/task/complete', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$task = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$task || $task['status'] != 200) {
|
||||
return Base::retError($task['message'] ?? '审批失败');
|
||||
@@ -260,12 +262,12 @@ class ApproveController extends AbstractController
|
||||
$this->approveMsg('approve_reviewer', $dialog, $botUser, $val, $process, $pass);
|
||||
}
|
||||
// 发起人
|
||||
if($process['is_finished'] == true) {
|
||||
if ($process['is_finished'] == true) {
|
||||
$dialog = WebSocketDialog::checkUserDialog($botUser, $process['start_user_id']);
|
||||
if (!empty($dialog)) {
|
||||
$this->approveMsg('approve_submitter', $dialog, $botUser, ['userid' => $data['userid']], $process, $pass);
|
||||
}
|
||||
}else if ($process['candidate']) {
|
||||
} else if ($process['candidate']) {
|
||||
// 下个审批人
|
||||
$userid = explode(',', $process['candidate']);
|
||||
$toUser = User::whereIn('userid', $userid)->get()->toArray();
|
||||
@@ -277,7 +279,7 @@ class ApproveController extends AbstractController
|
||||
if (empty($dialog)) {
|
||||
continue;
|
||||
}
|
||||
$this->approveMsg('approve_reviewer', $dialog, $botUser, $val, $process,'start');
|
||||
$this->approveMsg('approve_reviewer', $dialog, $botUser, $val, $process, 'start');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +293,7 @@ class ApproveController extends AbstractController
|
||||
}
|
||||
}
|
||||
}
|
||||
return Base::retSuccess( $pass == 'pass' ? '已通过' : '已拒绝', $task);
|
||||
return Base::retSuccess($pass == 'pass' ? '已通过' : '已拒绝', $task);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,7 +317,7 @@ class ApproveController extends AbstractController
|
||||
$data['userid'] = (string)$user->userid;
|
||||
$data['task_id'] = intval(Request::input('task_id'));
|
||||
$data['proc_inst_id'] = intval(Request::input('proc_inst_id'));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/task/withdraw', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/task/withdraw', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$task = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$task || $task['status'] != 200) {
|
||||
return Base::retError($task['message'] ?? '撤回失败');
|
||||
@@ -360,11 +362,12 @@ class ApproveController extends AbstractController
|
||||
{
|
||||
$user = User::auth();
|
||||
$data['userid'] = (string)$user->userid;
|
||||
$data['username'] = Request::input('username');
|
||||
$data['procName'] = Request::input('proc_def_name');
|
||||
$data['sort'] = Request::input('sort');
|
||||
$data['pageIndex'] = intval(Request::input('page'));
|
||||
$data['pageSize'] = intval(Request::input('page_size'));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/process/findTask', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/process/findTask', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '查询失败');
|
||||
@@ -378,7 +381,7 @@ class ApproveController extends AbstractController
|
||||
}
|
||||
$val['userimg'] = User::getAvatar($info->userid, $info->userimg, $info->email, $info->nickname);
|
||||
}
|
||||
return Base::retSuccess('success',$res);
|
||||
return Base::retSuccess('success', $res);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -402,11 +405,12 @@ class ApproveController extends AbstractController
|
||||
{
|
||||
$user = User::auth();
|
||||
$data['userid'] = (string)$user->userid;
|
||||
$data['username'] = Request::input('username');
|
||||
$data['procName'] = Request::input('proc_def_name'); //分类
|
||||
$data['state'] = intval(Request::input('state')); //状态
|
||||
$data['pageIndex'] = intval(Request::input('page'));
|
||||
$data['pageSize'] = intval(Request::input('page_size'));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/process/startByMyselfAll', json_encode($data));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/process/startByMyselfAll', json_encode($data));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '查询失败');
|
||||
@@ -444,7 +448,7 @@ class ApproveController extends AbstractController
|
||||
$data['userid'] = (string)$user->userid;
|
||||
$data['pageIndex'] = intval(Request::input('page'));
|
||||
$data['pageSize'] = intval(Request::input('page_size'));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/process/startByMyself', json_encode($data));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/process/startByMyself', json_encode($data));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '查询失败');
|
||||
@@ -488,7 +492,7 @@ class ApproveController extends AbstractController
|
||||
$data['pageIndex'] = intval(Request::input('page'));
|
||||
$data['pageSize'] = intval(Request::input('page_size'));
|
||||
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/process/findProcNotify', json_encode($data));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/process/findProcNotify', json_encode($data));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '查询失败');
|
||||
@@ -523,7 +527,7 @@ class ApproveController extends AbstractController
|
||||
{
|
||||
User::auth();
|
||||
$proc_inst_id = Request::input('proc_inst_id');
|
||||
$ret = Ihttp::ihttp_get($this->flow_url.'/api/v1/workflow/identitylink/findParticipant?procInstId=' . $proc_inst_id);
|
||||
$ret = Ihttp::ihttp_get($this->flow_url . '/api/v1/workflow/identitylink/findParticipant?procInstId=' . $proc_inst_id);
|
||||
$identitylink = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$identitylink || $identitylink['status'] != 200) {
|
||||
return Base::retError($identitylink['message'] ?? '查询失败');
|
||||
@@ -561,11 +565,12 @@ class ApproveController extends AbstractController
|
||||
{
|
||||
$user = User::auth();
|
||||
$data['userid'] = (string)$user->userid;
|
||||
$data['username'] = Request::input('username');
|
||||
$data['procName'] = Request::input('proc_def_name');
|
||||
$data['sort'] = Request::input('sort');
|
||||
$data['pageIndex'] = intval(Request::input('page'));
|
||||
$data['pageSize'] = intval(Request::input('page_size'));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/procHistory/findTask', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/procHistory/findTask', json_encode(Base::arrayKeyToCamel($data)));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '查询失败');
|
||||
@@ -603,7 +608,7 @@ class ApproveController extends AbstractController
|
||||
$data['userid'] = (string)$user->userid;
|
||||
$data['pageIndex'] = intval(Request::input('page'));
|
||||
$data['pageSize'] = intval(Request::input('page_size'));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/procHistory/startByMyself', json_encode($data));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/procHistory/startByMyself', json_encode($data));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '查询失败');
|
||||
@@ -641,12 +646,13 @@ class ApproveController extends AbstractController
|
||||
{
|
||||
$user = User::auth();
|
||||
$data['userid'] = (string)$user->userid;
|
||||
$data['username'] = Request::input('username');
|
||||
$data['procName'] = Request::input('proc_def_name');
|
||||
$data['sort'] = Request::input('sort');
|
||||
$data['pageIndex'] = intval(Request::input('page'));
|
||||
$data['pageSize'] = intval(Request::input('page_size'));
|
||||
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/procHistory/findProcNotify', json_encode($data));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/procHistory/findProcNotify', json_encode($data));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '查询失败');
|
||||
@@ -681,7 +687,7 @@ class ApproveController extends AbstractController
|
||||
{
|
||||
User::auth();
|
||||
$proc_inst_id = Request::input('proc_inst_id');
|
||||
$ret = Ihttp::ihttp_get($this->flow_url.'/api/v1/workflow/identitylinkHistory/findParticipant?procInstId=' . $proc_inst_id);
|
||||
$ret = Ihttp::ihttp_get($this->flow_url . '/api/v1/workflow/identitylinkHistory/findParticipant?procInstId=' . $proc_inst_id);
|
||||
$identitylink = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$identitylink || $identitylink['status'] != 200) {
|
||||
return Base::retError($identitylink['message'] ?? '查询失败');
|
||||
@@ -745,7 +751,7 @@ class ApproveController extends AbstractController
|
||||
$data['isFinished'] = intval(Request::input('is_finished')); //是否完成
|
||||
$date = Request::input('date');
|
||||
$data['startTime'] = $date[0]; //开始时间
|
||||
$data['endTime'] =Carbon::parse($date[1])->addDay()->toDateString(); //结束时间 + 1天
|
||||
$data['endTime'] = Carbon::parse($date[1])->addDay()->toDateString(); //结束时间 + 1天
|
||||
//
|
||||
if (empty($name) || empty($date)) {
|
||||
return Base::retError('参数错误');
|
||||
@@ -757,7 +763,7 @@ class ApproveController extends AbstractController
|
||||
return Base::retError('日期范围限制最大35天');
|
||||
}
|
||||
//
|
||||
$ret = Ihttp::ihttp_post($this->flow_url.'/api/v1/workflow/process/findAllProcIns', json_encode($data));
|
||||
$ret = Ihttp::ihttp_post($this->flow_url . '/api/v1/workflow/process/findAllProcIns', json_encode($data));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '查询失败');
|
||||
@@ -852,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);
|
||||
@@ -860,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);
|
||||
@@ -884,7 +890,8 @@ class ApproveController extends AbstractController
|
||||
}
|
||||
}
|
||||
|
||||
function getStateDescription($state) {
|
||||
function getStateDescription($state)
|
||||
{
|
||||
$state_map = array(
|
||||
0 => '全部',
|
||||
1 => '审批中',
|
||||
@@ -946,13 +953,13 @@ class ApproveController extends AbstractController
|
||||
}
|
||||
// 审批记录
|
||||
$name = $val['username'] . '|';
|
||||
$call = $val['step'] == 0 ? '发起审批'. '|' : '同意' . '|';
|
||||
$time =$val['step'] == 0 ? $process['start_time'] . '|' : '';
|
||||
$call = $val['step'] == 0 ? '发起审批' . '|' : '同意' . '|';
|
||||
$time = $val['step'] == 0 ? $process['start_time'] . '|' : '';
|
||||
$comment = $val['step'] == 0 ? '' : ($val['comment'] ?? '') . '|';
|
||||
$res['approval_record'] .= $name . $call . $time . $comment;
|
||||
}
|
||||
}
|
||||
$res['historical_approver'] = trim(implode(';', $historical_approver), ';');
|
||||
$res['historical_approver'] = trim(implode(';', $historical_approver), ';');
|
||||
$res['approved_node'] = $approved_node;
|
||||
$res['approved_num'] = $approved_num;
|
||||
$res['historical_agent'] = $res['historical_approver'];
|
||||
@@ -971,9 +978,13 @@ class ApproveController extends AbstractController
|
||||
'department' => $process['department'],
|
||||
'type' => $process['var']['type'],
|
||||
'start_time' => $process['var']['start_time'],
|
||||
'start_day_of_week' => '周' . Base::getTimeWeek(Carbon::parse($process['var']['start_time'])->timestamp),
|
||||
'end_time' => $process['var']['end_time'],
|
||||
'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);
|
||||
@@ -981,15 +992,15 @@ class ApproveController extends AbstractController
|
||||
$msg_action = null;
|
||||
if ($action == 'withdraw' || $action == 'pass' || $action == 'refuse') {
|
||||
// 任务完成,给发起人发送消息
|
||||
if($type == 'approve_submitter' && $action != 'withdraw'){
|
||||
return WebSocketDialogMsg::sendMsg($msg_action, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||
if ($type == 'approve_submitter' && $action != 'withdraw') {
|
||||
return WebSocketDialogMsg::sendMsg($msg_action, $dialog->id, 'text', ['text' => $text, 'approve_type' => $type], $botUser->userid, false, false, true);
|
||||
}
|
||||
// 查找最后一条消息msg_id
|
||||
$msg_action = 'update-'.$toUser['msg_id'];
|
||||
$msg_action = 'change-' . $toUser['msg_id'];
|
||||
}
|
||||
//
|
||||
try {
|
||||
$msg = WebSocketDialogMsg::sendMsg($msg_action, $dialog->id, 'text', ['text' => $text], $botUser->userid, false, false, true);
|
||||
$msg = WebSocketDialogMsg::sendMsg($msg_action, $dialog->id, 'text', ['text' => $text, 'approve_type' => $type], $botUser->userid, false, false, true);
|
||||
// 关联信息
|
||||
if ($action == 'start') {
|
||||
$proc_msg = new ApproveProcMsg();
|
||||
@@ -999,9 +1010,9 @@ class ApproveController extends AbstractController
|
||||
$proc_msg->save();
|
||||
}
|
||||
// 更新工作报告 未读数量
|
||||
if($type == 'approve_reviewer' && $toUser['userid']){
|
||||
if ($type == 'approve_reviewer' && $toUser['userid']) {
|
||||
$params = [
|
||||
'userid' => [ $toUser['userid'], User::auth()->userid() ],
|
||||
'userid' => [$toUser['userid'], User::auth()->userid()],
|
||||
'msg' => [
|
||||
'type' => 'approve',
|
||||
'action' => 'unread',
|
||||
@@ -1020,7 +1031,7 @@ class ApproveController extends AbstractController
|
||||
public function getProcessById($id)
|
||||
{
|
||||
$data['id'] = intval($id);
|
||||
$ret = Ihttp::ihttp_get($this->flow_url."/api/v1/workflow/process/findById?".http_build_query($data));
|
||||
$ret = Ihttp::ihttp_get($this->flow_url . "/api/v1/workflow/process/findById?" . http_build_query($data));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
throw new ApiException($process['message'] ?? '查询失败');
|
||||
@@ -1039,14 +1050,14 @@ class ApproveController extends AbstractController
|
||||
$val['node_user_list'][$k]['userimg'] = User::getAvatar($info->userid, $info->userimg, $info->email, $info->nickname);
|
||||
$res['userids'][] = $item['target_id'];
|
||||
}
|
||||
}else if($val['aprover_id']){
|
||||
} else if ($val['aprover_id']) {
|
||||
$info = User::whereUserid($val['aprover_id'])->first();
|
||||
$val['userimg'] = $info ? User::getAvatar($info->userid, $info->userimg, $info->email, $info->nickname) : '';
|
||||
$res['userids'][] = $val['aprover_id'];
|
||||
}
|
||||
}
|
||||
// 全局评论
|
||||
if(isset($res['global_comments'])){
|
||||
if (isset($res['global_comments'])) {
|
||||
foreach ($res['global_comments'] as $k => &$globalComment) {
|
||||
$info = User::whereUserid($globalComment['user_id'])->first();
|
||||
if (!$info) {
|
||||
@@ -1087,7 +1098,7 @@ class ApproveController extends AbstractController
|
||||
public function getUserProcessParticipantById($id)
|
||||
{
|
||||
$data['procInstId'] = intval($id);
|
||||
$ret = Ihttp::ihttp_get($this->flow_url."/api/v1/workflow/identitylink/findParticipantAll?".http_build_query($data));
|
||||
$ret = Ihttp::ihttp_get($this->flow_url . "/api/v1/workflow/identitylink/findParticipantAll?" . http_build_query($data));
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
throw new ApiException($process['message'] ?? '查询失败');
|
||||
@@ -1095,4 +1106,52 @@ class ApproveController extends AbstractController
|
||||
return $process;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @api {get} api/approve/user/status 20. 获取用户审批状态
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName user__status
|
||||
*
|
||||
* @apiParam {String} userid
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function user__status()
|
||||
{
|
||||
$data['userid'] = intval(Request::input('userid'));
|
||||
$ret = Ihttp::ihttp_get($this->flow_url . '/api/v1/workflow/process/getUserApprovalStatus?' . http_build_query($data));
|
||||
$procdef = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (isset($procdef['status']) && $procdef['status'] == 200) {
|
||||
return Base::retSuccess('success', isset($procdef['data']["proc_def_name"]) ? $procdef['data']["proc_def_name"] : '');
|
||||
}
|
||||
return Base::retSuccess('success', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/approve/process/doto 21. 查询需要我审批的流程数量
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup approve
|
||||
* @apiName process__doto
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function process__doto()
|
||||
{
|
||||
$user = User::auth();
|
||||
$ret = Ihttp::ihttp_get($this->flow_url . '/api/v1/workflow/process/findTaskTotal?userid=' . $user->userid);
|
||||
$process = json_decode($ret['ret'] == 1 ? $ret['data'] : '{}', true);
|
||||
if (!$process || $process['status'] != 200) {
|
||||
return Base::retError($process['message'] ?? '查询失败');
|
||||
}
|
||||
return Base::retSuccess('success', $process['data']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use App\Models\WebSocketDialog;
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Models\AbstractModel;
|
||||
use App\Models\File;
|
||||
@@ -11,9 +13,13 @@ use App\Models\FileUser;
|
||||
use App\Models\User;
|
||||
use App\Module\Base;
|
||||
use App\Module\Ihttp;
|
||||
use Response;
|
||||
use Session;
|
||||
use Swoole\Coroutine;
|
||||
use Carbon\Carbon;
|
||||
use Redirect;
|
||||
use Request;
|
||||
use ZipArchive;
|
||||
|
||||
/**
|
||||
* @apiDefine file
|
||||
@@ -478,7 +484,7 @@ class FileController extends AbstractController
|
||||
//
|
||||
if (Base::isNumber($id)) {
|
||||
$user = User::auth();
|
||||
$file = File::permissionFind(intval($id), $user);
|
||||
$file = File::permissionFind(intval($id), $user, $down == 'yes' ? 1 : 0);
|
||||
} elseif ($id) {
|
||||
$fileLink = FileLink::whereCode($id)->first();
|
||||
$file = $fileLink?->file;
|
||||
@@ -606,7 +612,32 @@ class FileController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/content/office 10. 保存文件内容(office)
|
||||
* @api {get} api/file/office/token 10. 获取token
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup file
|
||||
* @apiName office__token
|
||||
*
|
||||
* @apiParam {array} config
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function office__token()
|
||||
{
|
||||
User::auth();
|
||||
//
|
||||
$config = Request::input('config');
|
||||
$token = \Firebase\JWT\JWT::encode($config, env('APP_KEY') ,'HS256');
|
||||
return Base::retSuccess('成功', [
|
||||
'token' => $token
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/content/office 11. 保存文件内容(office)
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -660,7 +691,7 @@ class FileController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/content/upload 11. 保存文件内容(上传文件)
|
||||
* @api {get} api/file/content/upload 12. 保存文件内容(上传文件)
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -668,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错误)
|
||||
@@ -678,13 +712,14 @@ 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']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/content/history 12. 获取内容历史
|
||||
* @api {get} api/file/content/history 13. 获取内容历史
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -716,7 +751,7 @@ class FileController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/content/restore 13. 恢复文件历史
|
||||
* @api {get} api/file/content/restore 14. 恢复文件历史
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -756,7 +791,7 @@ class FileController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/share 14. 获取共享信息
|
||||
* @api {get} api/file/share 15. 获取共享信息
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -792,7 +827,7 @@ class FileController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/share/update 15. 设置共享
|
||||
* @api {get} api/file/share/update 16. 设置共享
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -882,7 +917,7 @@ class FileController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/share/out 16. 退出共享
|
||||
* @api {get} api/file/share/out 17. 退出共享
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -916,7 +951,7 @@ class FileController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/link 17. 获取链接
|
||||
* @api {get} api/file/link 18. 获取链接
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -944,4 +979,128 @@ class FileController extends AbstractController
|
||||
//
|
||||
return Base::retSuccess('success', $fileLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/file/download/pack 19. 打包文件
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup file
|
||||
* @apiName download__pack
|
||||
*
|
||||
* @apiParam {Array} [ids] 文件ID,格式: [id, id2, id3]
|
||||
* @apiParam {String} [name] 下载文件名
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function download__pack()
|
||||
{
|
||||
$key = Request::input('key');
|
||||
if ($key) {
|
||||
$userid = Session::get('file::pack:userid');
|
||||
if (empty($userid)) {
|
||||
return Base::ajaxError("请求已过期,请重新导出!", [], 0, 502);
|
||||
}
|
||||
//
|
||||
$array = Base::string2array(base64_decode(urldecode($key)));
|
||||
$file = $array['file'];
|
||||
if (empty($file) || !file_exists(storage_path($file))) {
|
||||
return Base::ajaxError("文件不存在!", [], 0, 502);
|
||||
}
|
||||
return Response::download(storage_path($file));
|
||||
}
|
||||
|
||||
$user = User::auth();
|
||||
$ids = Request::input('ids');
|
||||
$fileName = Request::input('name');
|
||||
$fileName = preg_replace("/[\/\\\:\*\?\"\<\>\|]/", "", $fileName);
|
||||
if (empty($fileName)) {
|
||||
$fileName = 'Package_' . $user->userid;
|
||||
}
|
||||
$fileName .= '_' . Base::time() . '.zip';
|
||||
|
||||
$filePath = "temp/file/pack/" . date("Ym", Base::time());
|
||||
$zipFile = "app/" . $filePath . "/" . $fileName;
|
||||
$zipPath = storage_path($zipFile);
|
||||
|
||||
if (!is_array($ids) || empty($ids)) {
|
||||
return Base::retError('请选择下载的文件或文件夹');
|
||||
}
|
||||
if (count($ids) > 100) {
|
||||
return Base::retError('一次最多可以下载100个文件或文件夹');
|
||||
}
|
||||
|
||||
$botUser = User::botGetOrCreate('system-msg');
|
||||
if (empty($botUser)) {
|
||||
return Base::retError('系统机器人不存在');
|
||||
}
|
||||
$dialog = WebSocketDialog::checkUserDialog($botUser, $user->userid);
|
||||
|
||||
$files = [];
|
||||
$totalSize = 0;
|
||||
|
||||
foreach ($ids as $k => $id) {
|
||||
$files[] = File::getFilesTree(intval($id), $user, 1);
|
||||
$totalSize += $files[$k]->totalSize;
|
||||
}
|
||||
|
||||
if ($totalSize > File::zipMaxSize) {
|
||||
return Base::retError('文件总大小已超过1GB,请分批下载');
|
||||
}
|
||||
|
||||
$base64 = base64_encode(Base::array2string([
|
||||
'file' => $zipFile,
|
||||
]));
|
||||
$fileUrl = Base::fillUrl('api/file/download/pack?key=' . urlencode($base64));
|
||||
Session::put('file::pack:userid', $user->userid);
|
||||
|
||||
$zip = new \ZipArchive();
|
||||
Base::makeDir(dirname($zipPath));
|
||||
|
||||
if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
||||
return Base::retError('创建压缩文件失败');
|
||||
}
|
||||
|
||||
go(function () use ($zipPath, $fileUrl, $zip, $files, $fileName, $botUser, $dialog) {
|
||||
Coroutine::sleep(0.1);
|
||||
// 压缩进度
|
||||
$progress = 0;
|
||||
$zip->registerProgressCallback(0.05, function ($ratio) use ($fileUrl, $fileName, &$progress) {
|
||||
$progress = round($ratio * 100);
|
||||
File::filePushMsg('compress', [
|
||||
'name' => $fileName,
|
||||
'url' => $fileUrl,
|
||||
'progress' => $progress
|
||||
]);
|
||||
});
|
||||
//
|
||||
foreach ($files as $file) {
|
||||
File::addFileTreeToZip($zip, $file);
|
||||
}
|
||||
$zip->close();
|
||||
//
|
||||
if ($progress < 100) {
|
||||
File::filePushMsg('compress', [
|
||||
'name' => $fileName,
|
||||
'url' => $fileUrl,
|
||||
'progress' => 100
|
||||
]);
|
||||
}
|
||||
//
|
||||
$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,
|
||||
'url' => $fileUrl,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,6 @@ use App\Module\Doo;
|
||||
use App\Tasks\PushTask;
|
||||
use Carbon\Carbon;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Request;
|
||||
@@ -317,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) {
|
||||
@@ -474,10 +476,13 @@ class ReportController extends AbstractController
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$data = Report::whereHas("Receives", function (Builder $query) use ($user) {
|
||||
$query->where("userid", $user->userid)->where("read", 0);
|
||||
})->orderByDesc('created_at')->paginate(Base::getPaginate(50, 20));
|
||||
return Base::retSuccess("success", $data);
|
||||
$total = Report::select('reports.id')
|
||||
->join('report_receives', 'report_receives.rid', '=', 'reports.id')
|
||||
->where('report_receives.userid', $user->userid)
|
||||
->where('report_receives.read', 0)
|
||||
->count();
|
||||
//
|
||||
return Base::retSuccess("success", compact("total"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,20 +60,27 @@ 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',
|
||||
'file_upload_limit',
|
||||
'unclaimed_task_reminder',
|
||||
'unclaimed_task_reminder_time',
|
||||
])) {
|
||||
unset($all[$key]);
|
||||
}
|
||||
@@ -93,27 +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('{}'));
|
||||
}
|
||||
@@ -189,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 返回数据
|
||||
@@ -209,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 {
|
||||
@@ -225,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('{}'));
|
||||
@@ -254,13 +273,17 @@ class SystemController extends AbstractController
|
||||
$keys = [
|
||||
'openai_key',
|
||||
'openai_agency',
|
||||
'openai_model',
|
||||
'claude_token',
|
||||
'claude_agency',
|
||||
'wenxin_key',
|
||||
'wenxin_secret',
|
||||
'wenxin_model',
|
||||
'qianwen_key',
|
||||
'qianwen_model'
|
||||
'qianwen_model',
|
||||
'gemini_key',
|
||||
'gemini_model',
|
||||
'gemini_agency',
|
||||
];
|
||||
|
||||
if ($type == 'save') {
|
||||
@@ -300,10 +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['wenxin_model'] = $setting['wenxin_model'] ?: 'ERNIE-Bot-turbo';
|
||||
$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) {
|
||||
@@ -377,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('{}'));
|
||||
}
|
||||
@@ -1183,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);
|
||||
@@ -1191,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);
|
||||
@@ -1248,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()
|
||||
{
|
||||
@@ -1271,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();
|
||||
}
|
||||
//
|
||||
@@ -633,6 +634,7 @@ class UsersController extends AbstractController
|
||||
$basic = UserDelete::userid2basic($id);
|
||||
}
|
||||
if ($basic) {
|
||||
//
|
||||
$retArray[] = $basic;
|
||||
}
|
||||
}
|
||||
@@ -766,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;
|
||||
@@ -1099,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 {
|
||||
@@ -1134,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;
|
||||
@@ -1154,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} 发起的会议";
|
||||
@@ -1178,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);
|
||||
@@ -1211,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;
|
||||
@@ -1222,7 +1236,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/meeting/link 16. 【会议】获取分享链接
|
||||
* @api {get} api/users/meeting/link 17. 【会议】获取分享链接
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1240,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();
|
||||
@@ -1251,7 +1265,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/meeting/tourist 16. 【会议】游客信息
|
||||
* @api {get} api/users/meeting/tourist 18. 【会议】游客信息
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1274,7 +1288,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/meeting/invitation 17. 【会议】发送邀请
|
||||
* @api {get} api/users/meeting/invitation 19. 【会议】发送邀请
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1321,7 +1335,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/email/send 18. 发送邮箱验证码
|
||||
* @api {get} api/users/email/send 20. 发送邮箱验证码
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1361,7 +1375,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/email/edit 19. 修改邮箱
|
||||
* @api {get} api/users/email/edit 21. 修改邮箱
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1406,7 +1420,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/delete/account 20. 删除帐号
|
||||
* @api {get} api/users/delete/account 22. 删除帐号
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1468,7 +1482,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/department/list 21. 部门列表(限管理员)
|
||||
* @api {get} api/users/department/list 23. 部门列表(限管理员)
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1487,7 +1501,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/department/add 22. 新建、修改部门(限管理员)
|
||||
* @api {get} api/users/department/add 24. 新建、修改部门(限管理员)
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1570,7 +1584,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/department/del 23. 删除部门(限管理员)
|
||||
* @api {get} api/users/department/del 25. 删除部门(限管理员)
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1600,7 +1614,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/checkin/get 24. 获取签到设置
|
||||
* @api {get} api/users/checkin/get 26. 获取签到设置
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1621,7 +1635,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} api/users/checkin/save 25. 保存签到设置
|
||||
* @api {post} api/users/checkin/save 27. 保存签到设置
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1669,7 +1683,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/checkin/list 26. 获取签到数据
|
||||
* @api {get} api/users/checkin/list 28. 获取签到数据
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1716,7 +1730,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/socket/status 27. 获取socket状态
|
||||
* @api {get} api/users/socket/status 29. 获取socket状态
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1739,7 +1753,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/key/client 28. 客户端KEY
|
||||
* @api {get} api/users/key/client 30. 客户端KEY
|
||||
*
|
||||
* @apiDescription 获取客户端KEY,用于加密数据发送给服务端
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1781,7 +1795,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/bot/info 29. 机器人信息
|
||||
* @api {get} api/users/bot/info 31. 机器人信息
|
||||
*
|
||||
* @apiDescription 需要token身份,获取我的机器人信息
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1832,7 +1846,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} api/users/bot/edit 30. 编辑机器人
|
||||
* @api {post} api/users/bot/edit 32. 编辑机器人
|
||||
*
|
||||
* @apiDescription 需要token身份,编辑 我的机器人 或 管理员修改系统机器人 信息
|
||||
* @apiVersion 1.0.0
|
||||
@@ -1918,7 +1932,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/share/list 31. 获取分享列表
|
||||
* @api {get} api/users/share/list 33. 获取分享列表
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup users
|
||||
@@ -1961,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",
|
||||
@@ -1970,7 +1984,7 @@ class UsersController extends AbstractController
|
||||
'name' => Doo::translate('文件'),
|
||||
];
|
||||
}
|
||||
$dialogList = (new WebSocketDialog)->getDialogList($user->userid);
|
||||
$dialogList = WebSocketDialog::getDialogList($user->userid);
|
||||
foreach ($dialogList['data'] as $dialog) {
|
||||
if ($dialog['avatar']) {
|
||||
$avatar = url($dialog['avatar']);
|
||||
@@ -2001,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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,25 +2,28 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Arr;
|
||||
use Cache;
|
||||
use Request;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use App\Module\Doo;
|
||||
use App\Models\File;
|
||||
use App\Module\Base;
|
||||
use App\Module\Extranet;
|
||||
use App\Module\RandomColor;
|
||||
use App\Tasks\LoopTask;
|
||||
use App\Tasks\AppPushTask;
|
||||
use App\Tasks\AutoArchivedTask;
|
||||
use App\Tasks\CheckinRemindTask;
|
||||
use App\Tasks\DeleteBotMsgTask;
|
||||
use App\Tasks\JokeSoupTask;
|
||||
use App\Tasks\DeleteTmpTask;
|
||||
use App\Tasks\EmailNoticeTask;
|
||||
use App\Tasks\JokeSoupTask;
|
||||
use App\Tasks\LoopTask;
|
||||
use Arr;
|
||||
use Cache;
|
||||
use App\Tasks\AutoArchivedTask;
|
||||
use App\Tasks\DeleteBotMsgTask;
|
||||
use App\Tasks\CheckinRemindTask;
|
||||
use App\Tasks\CloseMeetingRoomTask;
|
||||
use App\Tasks\UnclaimedTaskRemindTask;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use LasseRafn\InitialAvatarGenerator\InitialAvatar;
|
||||
use Redirect;
|
||||
use Request;
|
||||
use Response;
|
||||
|
||||
|
||||
/**
|
||||
@@ -36,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';
|
||||
@@ -67,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.3.2-8/web-apps/vendor/requirejs/require.js",
|
||||
"office/7.3.2-8/web-apps/apps/api/documents/api.js",
|
||||
"office/7.3.2-8/sdkjs/common/AllFonts.js",
|
||||
"office/7.3.2-8/web-apps/vendor/xregexp/xregexp-all-min.js",
|
||||
"office/7.3.2-8/web-apps/vendor/sockjs/sockjs.min.js",
|
||||
"office/7.3.2-8/web-apps/vendor/jszip/jszip.min.js",
|
||||
"office/7.3.2-8/web-apps/vendor/jszip-utils/jszip-utils.min.js",
|
||||
"office/7.3.2-8/sdkjs/common/libfont/wasm/fonts.js",
|
||||
"office/7.3.2-8/sdkjs/common/Charts/ChartStyles.js",
|
||||
"office/7.3.2-8/sdkjs/slide/themes//themes.js",
|
||||
|
||||
"office/7.3.2-8/web-apps/apps/presentationeditor/main/app.js",
|
||||
"office/7.3.2-8/sdkjs/slide/sdk-all-min.js",
|
||||
"office/7.3.2-8/sdkjs/slide/sdk-all.js",
|
||||
|
||||
"office/7.3.2-8/web-apps/apps/documenteditor/main/app.js",
|
||||
"office/7.3.2-8/sdkjs/word/sdk-all-min.js",
|
||||
"office/7.3.2-8/sdkjs/word/sdk-all.js",
|
||||
|
||||
"office/7.3.2-8/web-apps/apps/spreadsheeteditor/main/app.js",
|
||||
"office/7.3.2-8/sdkjs/cell/sdk-all-min.js",
|
||||
"office/7.3.2-8/sdkjs/cell/sdk-all.js",
|
||||
];
|
||||
foreach ($array as &$item) {
|
||||
$item = url($item);
|
||||
}
|
||||
return implode(PHP_EOL, $array);
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,6 +155,7 @@ class IndexController extends InvokeController
|
||||
Task::deliver(new DeleteTmpTask('task_worker', 12));
|
||||
Task::deliver(new DeleteTmpTask('tmp'));
|
||||
Task::deliver(new DeleteTmpTask('file'));
|
||||
Task::deliver(new DeleteTmpTask('file_pack'));
|
||||
// 删除机器人消息
|
||||
Task::deliver(new DeleteBotMsgTask());
|
||||
// 周期任务
|
||||
@@ -203,6 +164,10 @@ class IndexController extends InvokeController
|
||||
Task::deliver(new CheckinRemindTask());
|
||||
// 获取笑话/心灵鸡汤
|
||||
Task::deliver(new JokeSoupTask());
|
||||
// 未领取任务通知
|
||||
Task::deliver(new UnclaimedTaskRemindTask());
|
||||
// 关闭会议室
|
||||
Task::deliver(new CloseMeetingRoomTask());
|
||||
|
||||
return "success";
|
||||
}
|
||||
@@ -213,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') {
|
||||
@@ -220,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");
|
||||
@@ -234,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;
|
||||
}
|
||||
@@ -245,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),
|
||||
];
|
||||
}
|
||||
@@ -269,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),
|
||||
];
|
||||
}
|
||||
@@ -317,45 +300,90 @@ class IndexController extends InvokeController
|
||||
$data = parse_url($key);
|
||||
$path = Arr::get($data, 'path');
|
||||
$file = public_path($path);
|
||||
// 防止 ../ 穿越获取到系统文件
|
||||
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 -->';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -236,10 +236,9 @@ class AbstractModel extends Model
|
||||
info($eb);
|
||||
}
|
||||
if ($e instanceof ApiException) {
|
||||
throw new ApiException($e->getMessage(), $e->getData(), $e->getCode());
|
||||
throw new ApiException( $e->getMessage() , $e->getData(), $e->getCode());
|
||||
} else {
|
||||
info($e);
|
||||
throw new ApiException($e->getMessage() ?: '处理错误');
|
||||
throw new ApiException( $e->getMessage() ?: '处理错误');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,20 +6,24 @@ namespace App\Models;
|
||||
* App\Models\ApproveProcMsg
|
||||
*
|
||||
* @property int $id
|
||||
* @property string|null $type 信息类型(如:candidate-候选人、participant-参与人、notifier-抄送人)
|
||||
* @property int|null $proc_inst_id 流程实例ID
|
||||
* @property int|null $userid 会员ID
|
||||
* @property int|null $msg_id 消息ID
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|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)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ApproveProcMsg whereProcInstId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ApproveProcMsg whereType($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ApproveProcMsg whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ApproveProcMsg whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
|
||||
@@ -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)
|
||||
@@ -81,11 +87,13 @@ class Deleted extends AbstractModel
|
||||
{
|
||||
$array = is_array($userid) ? $userid : [$userid];
|
||||
foreach ($array as $value) {
|
||||
self::updateInsert([
|
||||
'type' => $type,
|
||||
'did' => $id,
|
||||
'userid' => $value,
|
||||
]);
|
||||
if (!self::where('type', $type)->where('did', $id)->where('userid', $value)->exists()) {
|
||||
self::updateInsert([
|
||||
'type' => $type,
|
||||
'did' => $id,
|
||||
'userid' => $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)
|
||||
@@ -95,6 +101,11 @@ class File extends AbstractModel
|
||||
'avi', 'mov', 'wmv', 'mkv', '3gp', 'rm',
|
||||
];
|
||||
|
||||
/**
|
||||
* 压缩包下载大小限制
|
||||
*/
|
||||
const zipMaxSize = 1024 * 1024 * 1024; // 1G
|
||||
|
||||
|
||||
/**
|
||||
* 获取文件列表
|
||||
@@ -185,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) {
|
||||
@@ -233,15 +245,17 @@ class File extends AbstractModel
|
||||
}
|
||||
}
|
||||
//
|
||||
$setting = Base::setting('system');
|
||||
$path = 'uploads/tmp/' . date("Ym") . '/';
|
||||
$data = Base::upload([
|
||||
"file" => Request::file('files'),
|
||||
"type" => 'more',
|
||||
"autoThumb" => false,
|
||||
"path" => $path,
|
||||
"size" => ($setting['file_upload_limit'] ?: 0) * 1024
|
||||
]);
|
||||
if (Base::isError($data)) {
|
||||
return $data;
|
||||
throw new ApiException($data['msg']);
|
||||
}
|
||||
$data = $data['data'];
|
||||
//
|
||||
@@ -276,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();
|
||||
//
|
||||
@@ -314,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];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -832,4 +855,106 @@ class File extends AbstractModel
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件树并计算文件总大小
|
||||
*
|
||||
* @param int $fileId
|
||||
* @param User $user
|
||||
* @param int $permission 0-访问权限、1-读写权限、1000-所有者或创建者
|
||||
* @param string $path
|
||||
* @param int $totalSize
|
||||
* @return object
|
||||
*/
|
||||
public static function getFilesTree(int $fileId, User $user, $permission = 1, $path = '', &$totalSize = 0) {
|
||||
$file = File::permissionFind($fileId, $user, $permission);
|
||||
$file->path = ltrim($path . '/' . $file->name, '/');
|
||||
$file->children = [];
|
||||
if ($file->type == 'folder') {
|
||||
$files = $file->getFileList($user, $fileId, 'all', false);
|
||||
foreach ($files as &$childFile) {
|
||||
$childFile['path'] = $file->path . '/' . $childFile['name'];
|
||||
if ($childFile['type'] == 'folder') {
|
||||
$childFile['children'] = self::getFilesTree($childFile['id'], $user, $permission, $file->path, $totalSize);
|
||||
} else {
|
||||
$totalSize += $childFile['size'];
|
||||
}
|
||||
}
|
||||
$file->children = $files;
|
||||
} else {
|
||||
$totalSize += $file->size;
|
||||
}
|
||||
$file->totalSize = $totalSize;
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件夹文件添加到压缩文件
|
||||
*
|
||||
* @param \ZipArchive $zip
|
||||
* @param object $file
|
||||
* @return void
|
||||
*/
|
||||
public static function addFileTreeToZip($zip, $file)
|
||||
{
|
||||
if ($file->type != 'folder' && $file->name != '') {
|
||||
$content = FileContent::whereFid($file->id)->orderByDesc('id')->first();
|
||||
$content = Base::json2array($content?->content ?: []);
|
||||
$typeExtensions = [
|
||||
'word' => 'docx',
|
||||
'excel' => 'xlsx',
|
||||
'ppt' => 'pptx',
|
||||
];
|
||||
if (array_key_exists($file->type, $typeExtensions)) {
|
||||
$filePath = empty($content) ? public_path('assets/office/empty.' . $typeExtensions[$file->type]) : public_path($content['url']);
|
||||
}
|
||||
//
|
||||
$relativePath = $file->path . '.' . $file->ext;
|
||||
if (file_exists($filePath)) {
|
||||
$zip->addFile($filePath, $relativePath);
|
||||
} else {
|
||||
if (empty($content['url'])) {
|
||||
$zip->addFromString($relativePath, $content['content']);
|
||||
} else {
|
||||
$filePath = public_path($content['url']);
|
||||
$zip->addFile($filePath, $relativePath);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isset($file->children)) {
|
||||
foreach ($file->children as $childFile) {
|
||||
try {
|
||||
self::addFileTreeToZip($zip, (object)$childFile);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 在压缩包中创建文件夹
|
||||
$zip->addEmptyDir($file->path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件推送消息
|
||||
* @param $action
|
||||
* @param array|null $data 发送内容
|
||||
* @param array $userid 会员ID
|
||||
*/
|
||||
public static function filePushMsg($action, $data = null, $userid = null)
|
||||
{
|
||||
$userid = User::auth()->userid();
|
||||
if (empty($userid)) {
|
||||
return;
|
||||
}
|
||||
$msg = [
|
||||
'type' => 'file',
|
||||
'action' => $action,
|
||||
'data' => $data,
|
||||
];
|
||||
$params = [
|
||||
'userid' => $userid,
|
||||
'msg' => $msg
|
||||
];
|
||||
Task::deliver(new PushTask($params));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,9 +118,7 @@ class FileContent extends AbstractModel
|
||||
} else {
|
||||
$filePath = public_path($content['url']);
|
||||
}
|
||||
return Base::streamDownload(function() use ($filePath) {
|
||||
echo file_get_contents($filePath);
|
||||
}, $name);
|
||||
return Base::streamDownload($filePath, $name);
|
||||
}
|
||||
if (empty($content)) {
|
||||
$content = match ($file->type) {
|
||||
@@ -143,9 +147,7 @@ class FileContent extends AbstractModel
|
||||
if ($download) {
|
||||
$filePath = public_path($path);
|
||||
if (isset($filePath)) {
|
||||
return Base::streamDownload(function() use ($filePath) {
|
||||
echo file_get_contents($filePath);
|
||||
}, $name);
|
||||
return Base::streamDownload($filePath, $name);
|
||||
} else {
|
||||
abort(403, "This file not support download.");
|
||||
}
|
||||
|
||||
@@ -15,9 +15,15 @@ use App\Module\Base;
|
||||
* @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)
|
||||
|
||||
@@ -14,13 +14,19 @@ use Illuminate\Support\Carbon;
|
||||
* @property string|null $name 会议主题
|
||||
* @property string|null $channel 频道
|
||||
* @property int|null $userid 创建人
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property Carbon|null $created_at
|
||||
* @property Carbon|null $updated_at
|
||||
* @property string|null $end_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_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)
|
||||
@@ -68,7 +74,9 @@ class ProjectColumn extends AbstractModel
|
||||
AbstractModel::transaction(function () use ($pushMsg) {
|
||||
$tasks = ProjectTask::whereColumnId($this->id)->get();
|
||||
foreach ($tasks as $task) {
|
||||
$task->deleteTask($pushMsg);
|
||||
if(!$task->archived_at){
|
||||
$task->deleteTask($pushMsg);
|
||||
}
|
||||
}
|
||||
$this->delete();
|
||||
$this->addLog("删除列表:" . $this->name);
|
||||
@@ -119,7 +127,7 @@ class ProjectColumn extends AbstractModel
|
||||
$userid = $this->project->relationUserids();
|
||||
}
|
||||
$params = [
|
||||
'ignoreFd' => Request::header('fd'),
|
||||
'ignoreFd' => $action == 'recovery' ? 0 : Request::header('fd'),
|
||||
'userid' => $userid,
|
||||
'msg' => [
|
||||
'type' => 'projectColumn',
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
207
app/Models/ProjectPermission.php
Normal file
207
app/Models/ProjectPermission.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Module\Base;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectPermission
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @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)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectPermission whereProjectId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectPermission whereUpdatedAt($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ProjectPermission extends AbstractModel
|
||||
{
|
||||
|
||||
const TASK_LIST_ADD = 'task_list_add'; // 添加列
|
||||
const TASK_LIST_UPDATE = 'task_list_update'; // 修改列
|
||||
const TASK_LIST_REMOVE = 'task_list_remove'; // 删除列
|
||||
const TASK_LIST_SORT = 'task_list_sort'; // 列表排序
|
||||
const TASK_ADD = 'task_add'; // 任务添加
|
||||
const TASK_UPDATE = 'task_update'; // 任务更新
|
||||
const TASK_STATUS = 'task_status'; // 任务状态
|
||||
const TASK_REMOVE = 'task_remove'; // 任务删除
|
||||
const TASK_ARCHIVED = 'task_archived'; // 任务归档
|
||||
const TASK_MOVE = 'task_move'; // 任务移动
|
||||
|
||||
// 权限列表
|
||||
const PERMISSIONS = [
|
||||
'project_leader' => 1, // 项目负责人
|
||||
'project_member' => 2, // 项目成员
|
||||
'task_leader' => 3, // 任务负责人
|
||||
'task_assist' => 4, // 任务协助人
|
||||
];
|
||||
|
||||
// 权限描述
|
||||
const PERMISSIONS_DESC = [
|
||||
1 => "项目负责人",
|
||||
2 => "项目成员",
|
||||
3 => "任务负责人",
|
||||
4 => "任务协助人",
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['project_id', 'permissions'];
|
||||
|
||||
/**
|
||||
* 权限
|
||||
* @param $value
|
||||
* @return string
|
||||
*/
|
||||
public function getPermissionsAttribute($value)
|
||||
{
|
||||
return Base::json2array($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限值
|
||||
*
|
||||
* @param int $projectId
|
||||
* @param string $key
|
||||
* @return object|array
|
||||
*/
|
||||
public static function getPermission($projectId, $key = '')
|
||||
{
|
||||
$projectPermission = self::initPermissions($projectId);
|
||||
$currentPermissions = $projectPermission->permissions;
|
||||
if ($key) {
|
||||
if (!isset($currentPermissions[$key])) {
|
||||
throw new ApiException('项目权限设置不存在');
|
||||
}
|
||||
return $currentPermissions[$key];
|
||||
}
|
||||
return $projectPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化项目权限
|
||||
*
|
||||
* @param int $projectId
|
||||
* @return ProjectPermission
|
||||
*/
|
||||
public static function initPermissions($projectId)
|
||||
{
|
||||
$permissions = [
|
||||
self::TASK_LIST_ADD => $projectTaskList = [self::PERMISSIONS['project_leader'], self::PERMISSIONS['project_member']],
|
||||
self::TASK_LIST_UPDATE => $projectTaskList,
|
||||
self::TASK_LIST_REMOVE => [self::PERMISSIONS['project_leader']],
|
||||
self::TASK_LIST_SORT => $projectTaskList,
|
||||
self::TASK_ADD => $projectTaskList,
|
||||
self::TASK_UPDATE => [self::PERMISSIONS['project_leader'], self::PERMISSIONS['task_leader'], self::PERMISSIONS['task_assist']],
|
||||
self::TASK_STATUS => $taskStatus = [self::PERMISSIONS['project_leader'], self::PERMISSIONS['task_leader']],
|
||||
self::TASK_REMOVE => $taskStatus,
|
||||
self::TASK_ARCHIVED => $taskStatus,
|
||||
self::TASK_MOVE => $taskStatus
|
||||
];
|
||||
return self::firstOrCreate(
|
||||
['project_id' => $projectId],
|
||||
['permissions' => Base::array2json($permissions)]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新项目权限
|
||||
*
|
||||
* @param int $projectId
|
||||
* @param array $permissions
|
||||
* @return ProjectPermission
|
||||
*/
|
||||
public static function updatePermissions($projectId, $newPermissions)
|
||||
{
|
||||
$projectPermission = self::initPermissions($projectId);
|
||||
$currentPermissions = $projectPermission->permissions;
|
||||
$mergedPermissions = empty($newPermissions) ? $currentPermissions : array_merge($currentPermissions, $newPermissions);
|
||||
|
||||
$projectPermission->permissions = Base::array2json($mergedPermissions);
|
||||
$projectPermission->save();
|
||||
|
||||
return $projectPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否有执行特定动作的权限
|
||||
* @param string $action 动作名称
|
||||
* @param Project $project 项目实例
|
||||
* @param ProjectTask $task 任务实例
|
||||
* @return bool
|
||||
*/
|
||||
public static function userTaskPermission(Project $project, $action, ProjectTask $task = null)
|
||||
{
|
||||
$userid = User::userid();
|
||||
$permissions = self::getPermission($project->id, $action);
|
||||
switch ($action) {
|
||||
// 任务添加,任务更新, 任务状态, 任务删除, 任务完成, 任务归档, 任务移动
|
||||
case self::TASK_LIST_ADD:
|
||||
case self::TASK_LIST_UPDATE:
|
||||
case self::TASK_LIST_REMOVE:
|
||||
case self::TASK_LIST_SORT:
|
||||
case self::TASK_ADD:
|
||||
case self::TASK_UPDATE:
|
||||
case self::TASK_STATUS:
|
||||
case self::TASK_REMOVE:
|
||||
case self::TASK_ARCHIVED:
|
||||
case self::TASK_MOVE:
|
||||
$verify = false;
|
||||
// 项目负责人
|
||||
if (in_array(self::PERMISSIONS['project_leader'], $permissions)) {
|
||||
if ($project->owner) {
|
||||
$verify = true;
|
||||
}
|
||||
}
|
||||
// 项目成员
|
||||
if (!$verify && in_array(self::PERMISSIONS['project_member'], $permissions)) {
|
||||
$user = ProjectUser::whereProjectId($project->id)->whereUserid(intval($userid))->first();
|
||||
if (!empty($user)) {
|
||||
$verify = true;
|
||||
}
|
||||
}
|
||||
// 任务负责人
|
||||
if (!$verify && $task && in_array(self::PERMISSIONS['task_leader'], $permissions)) {
|
||||
if ($task->isOwner()) {
|
||||
$verify = true;
|
||||
}
|
||||
}
|
||||
// 任务协助人
|
||||
if (!$verify && $task && in_array(self::PERMISSIONS['task_assist'], $permissions)) {
|
||||
if ($task->isAssister()) {
|
||||
$verify = true;
|
||||
}
|
||||
}
|
||||
//
|
||||
if (!$verify) {
|
||||
$desc = [];
|
||||
rsort($permissions);
|
||||
foreach ($permissions as $permission) {
|
||||
$desc[] = self::PERMISSIONS_DESC[$permission];
|
||||
}
|
||||
$desc = array_reverse($desc);
|
||||
throw new ApiException(sprintf("仅限%s操作", implode('、', $desc)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2,15 +2,16 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use DB;
|
||||
use Arr;
|
||||
use Request;
|
||||
use Carbon\Carbon;
|
||||
use App\Module\Base;
|
||||
use App\Tasks\PushTask;
|
||||
use Arr;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use App\Exceptions\ApiException;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use App\Models\ProjectTaskVisibilityUser;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Request;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectTask
|
||||
@@ -32,6 +33,7 @@ use Request;
|
||||
* @property int|null $archived_follow 跟随项目归档(项目取消归档时任务也取消归档)
|
||||
* @property string|null $complete_at 完成时间
|
||||
* @property int|null $userid 创建人
|
||||
* @property int|null $visibility 任务可见性:1-项目人员 2-任务人员 3-指定成员
|
||||
* @property int|null $p_level 优先级
|
||||
* @property string|null $p_name 优先级名称
|
||||
* @property string|null $p_color 优先级颜色
|
||||
@@ -61,10 +63,16 @@ use Request;
|
||||
* @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)
|
||||
@@ -92,6 +100,7 @@ use Request;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereStartAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereUserid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask whereVisibility($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask withTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTask withoutTrashed()
|
||||
* @mixin \Eloquent
|
||||
@@ -326,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:
|
||||
@@ -371,7 +374,7 @@ class ProjectTask extends AbstractModel
|
||||
$p_color = $data['p_color'];
|
||||
$top = intval($data['top']);
|
||||
$userid = User::userid();
|
||||
$is_all_visible = isset($data['visibility_appoint']) ? $data['visibility_appoint'] : $data['is_all_visible'];
|
||||
$visibility = isset($data['visibility_appoint']) ? $data['visibility_appoint'] : $data['visibility'];
|
||||
$visibility_userids = $data['visibility_appointor'] ?: [];
|
||||
//
|
||||
if (ProjectTask::whereProjectId($project_id)
|
||||
@@ -401,7 +404,7 @@ class ProjectTask extends AbstractModel
|
||||
'p_level' => $p_level,
|
||||
'p_name' => $p_name,
|
||||
'p_color' => $p_color,
|
||||
'is_all_visible' => $is_all_visible ?: 1
|
||||
'visibility' => $visibility ?: 1
|
||||
]);
|
||||
if ($content) {
|
||||
$task->desc = Base::getHtml($content, 100);
|
||||
@@ -492,13 +495,12 @@ class ProjectTask extends AbstractModel
|
||||
])->save();
|
||||
}
|
||||
|
||||
// 可见性
|
||||
foreach ($visibility_userids as $uid) {
|
||||
ProjectTaskUser::createInstance([
|
||||
ProjectTaskVisibilityUser::createInstance([
|
||||
'project_id' => $task->project_id,
|
||||
'task_id' => $task->id,
|
||||
'task_pid' => $task->parent_id ?: $task->id,
|
||||
'userid' => $uid,
|
||||
'owner' => 2,
|
||||
'userid' => $uid
|
||||
])->save();
|
||||
}
|
||||
|
||||
@@ -547,15 +549,12 @@ class ProjectTask extends AbstractModel
|
||||
*/
|
||||
public function updateTask($data, &$updateMarking = [])
|
||||
{
|
||||
//
|
||||
AbstractModel::transaction(function () use ($data, &$updateMarking) {
|
||||
// 主任务
|
||||
$mainTask = $this->parent_id > 0 ? self::find($this->parent_id) : null;
|
||||
// 工作流
|
||||
if (Arr::exists($data, 'flow_item_id')) {
|
||||
$isProjectOwner = $this->useridInTheProject(User::userid()) === 2;
|
||||
if (!$isProjectOwner && !$this->isOwner()) {
|
||||
throw new ApiException('仅限项目或任务负责人修改任务状态');
|
||||
}
|
||||
if ($this->flow_item_id == $data['flow_item_id']) {
|
||||
throw new ApiException('任务状态未发生改变');
|
||||
}
|
||||
@@ -576,6 +575,7 @@ class ProjectTask extends AbstractModel
|
||||
throw new ApiException("当前状态[{$currentFlowItem->name}]不可流转到[{$newFlowItem->name}]");
|
||||
}
|
||||
if ($currentFlowItem->userlimit) {
|
||||
$isProjectOwner = $this->useridInTheProject(User::userid()) === 2;
|
||||
if (!$isProjectOwner && !in_array(User::userid(), $currentFlowItem->userids)) {
|
||||
throw new ApiException("当前状态[{$currentFlowItem->name}]仅限状态负责人或项目负责人修改");
|
||||
}
|
||||
@@ -722,21 +722,19 @@ class ProjectTask extends AbstractModel
|
||||
$this->syncDialogUser();
|
||||
}
|
||||
// 可见性
|
||||
if (Arr::exists($data, 'is_all_visible') || Arr::exists($data, 'visibility_appointor')) {
|
||||
if (Arr::exists($data, 'is_all_visible')) {
|
||||
ProjectTask::whereId($data['task_id'])->update(['is_all_visible' => $data["is_all_visible"]]);
|
||||
ProjectTask::whereParentId($data['task_id'])->update(['is_all_visible' => $data["is_all_visible"]]);
|
||||
if (Arr::exists($data, 'visibility') || Arr::exists($data, 'visibility_appointor')) {
|
||||
if (Arr::exists($data, 'visibility')) {
|
||||
ProjectTask::whereId($data['task_id'])->update(['visibility' => $data["visibility"]]);
|
||||
ProjectTask::whereParentId($data['task_id'])->update(['visibility' => $data["visibility"]]);
|
||||
}
|
||||
ProjectTaskUser::whereTaskId($data['task_id'])->whereOwner(2)->delete();
|
||||
ProjectTaskVisibilityUser::whereTaskId($data['task_id'])->delete();
|
||||
if (Arr::exists($data, 'visibility_appointor')) {
|
||||
foreach ($data['visibility_appointor'] as $uid) {
|
||||
if ($uid) {
|
||||
ProjectTaskUser::createInstance([
|
||||
ProjectTaskVisibilityUser::createInstance([
|
||||
'project_id' => $this->project_id,
|
||||
'task_id' => $this->id,
|
||||
'task_pid' => $this->parent_id ?: $this->id,
|
||||
'userid' => $uid,
|
||||
'owner' => 2,
|
||||
'userid' => $uid
|
||||
])->save();
|
||||
}
|
||||
}
|
||||
@@ -1287,6 +1285,13 @@ class ProjectTask extends AbstractModel
|
||||
}
|
||||
AbstractModel::transaction(function () use ($isAuto, $archived_at) {
|
||||
if ($archived_at === null) {
|
||||
// 还原任务栏
|
||||
if (!$this->projectColumn) {
|
||||
$this->projectColumn()->restore();
|
||||
if($projectColumn = $this->projectColumn()->first()){
|
||||
$projectColumn->pushMsg('recovery', $projectColumn);
|
||||
}
|
||||
}
|
||||
// 取消归档
|
||||
$this->archived_at = null;
|
||||
$this->archived_userid = User::userid();
|
||||
@@ -1425,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['is_all_visible'] == 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'),
|
||||
@@ -1511,8 +1525,11 @@ class ProjectTask extends AbstractModel
|
||||
$array = [];
|
||||
if ($pushUserIds) {
|
||||
$userids = $pushUserIds;
|
||||
} elseif ($this->is_all_visible != 1) {
|
||||
$userids = ProjectTaskUser::select(['userid', 'owner'])->whereTaskId($this->id)->orWhere('task_pid', '=', $this->id)->pluck('userid')->toArray();
|
||||
} elseif ($this->visibility != 1) {
|
||||
$userids = ProjectTaskUser::whereTaskId($this->id)->orWhere('task_pid', '=', $this->id)->pluck('userid')->toArray();
|
||||
if ($this->visibility == 3) {
|
||||
$userids = array_merge($userids, ProjectTaskVisibilityUser::whereTaskId($this->id)->pluck('userid')->toArray());
|
||||
}
|
||||
} else {
|
||||
$userids = ProjectUser::whereProjectId($this->project_id)->pluck('userid')->toArray(); // 项目成员
|
||||
}
|
||||
@@ -1656,6 +1673,63 @@ class ProjectTask extends AbstractModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动任务
|
||||
* @param int $project_id
|
||||
* @param int $column_id
|
||||
* @param int $flowItemId
|
||||
* @param array $owner
|
||||
* @param array $assist
|
||||
* @return bool
|
||||
*/
|
||||
public function moveTask(int $projectId, int $columnId,int $flowItemId = 0,array $owner = [], array $assist = [])
|
||||
{
|
||||
AbstractModel::transaction(function () use($projectId, $columnId, $flowItemId, $owner, $assist) {
|
||||
$newTaskUser = array_merge($owner, $assist);
|
||||
//
|
||||
$this->project_id = $projectId;
|
||||
$this->column_id = $columnId;
|
||||
$this->flow_item_id = $flowItemId;
|
||||
// 任务内容
|
||||
if($this->content){
|
||||
$this->content->project_id = $projectId;
|
||||
$this->content->save();
|
||||
}
|
||||
// 任务文件
|
||||
foreach ($this->taskFile as $taskFile){
|
||||
$taskFile->project_id = $projectId;
|
||||
$taskFile->save();
|
||||
}
|
||||
// 任务标签
|
||||
foreach ($this->taskTag as $taskTag){
|
||||
$taskTag->project_id = $projectId;
|
||||
$taskTag->save();
|
||||
}
|
||||
// 任务用户
|
||||
$this->updateTask(['owner' => $owner]);
|
||||
$this->updateTask(['assist' => $assist]);
|
||||
foreach ($this->taskUser as $taskUser){
|
||||
if( in_array($taskUser->id, $newTaskUser) ){
|
||||
$taskUser->project_id = $projectId;
|
||||
$taskUser->save();
|
||||
}
|
||||
}
|
||||
//
|
||||
if($flowItemId){
|
||||
$flowItem = projectFlowItem::whereProjectId($projectId)->whereId($flowItemId)->first();
|
||||
$this->flow_item_name = $flowItem->status . "|" . $flowItem->name;
|
||||
}else{
|
||||
$this->flow_item_name = '';
|
||||
}
|
||||
//
|
||||
$this->save();
|
||||
//
|
||||
$this->addLog("移动{任务}");
|
||||
});
|
||||
$this->pushMsg('update');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务
|
||||
* @param $task_id
|
||||
@@ -1679,14 +1753,10 @@ class ProjectTask extends AbstractModel
|
||||
* @param int $task_id
|
||||
* @param bool $archived true:仅限未归档, false:仅限已归档, null:不限制
|
||||
* @param bool $trashed true:仅限未删除, false:仅限已删除, null:不限制
|
||||
* @param int|bool $permission
|
||||
* - 0|false 限制:项目成员、任务成员、任务群聊成员(任务成员 = 任务创建人+任务协助人+任务负责人)
|
||||
* - 1|true 限制:项目负责人、任务成员
|
||||
* - 2 已有负责人才限制true (子任务时如果是主任务负责人也可以)
|
||||
* @param array $with
|
||||
* @return self
|
||||
*/
|
||||
public static function userTask($task_id, $archived = true, $trashed = true, $permission = false, $with = [])
|
||||
public static function userTask($task_id, $archived = true, $trashed = true, $with = [])
|
||||
{
|
||||
$builder = self::with($with)->allData()->where("project_tasks.id", intval($task_id));
|
||||
if ($trashed === false) {
|
||||
@@ -1709,7 +1779,7 @@ class ProjectTask extends AbstractModel
|
||||
try {
|
||||
$project = Project::userProject($task->project_id);
|
||||
} catch (\Throwable $e) {
|
||||
if ($task->owner !== null || (!$permission && $task->permission(4))) {
|
||||
if ($task->owner !== null || $task->permission(4)) {
|
||||
$project = Project::find($task->project_id);
|
||||
if (empty($project)) {
|
||||
throw new ApiException('项目不存在或已被删除', [ 'task_id' => $task_id ], -4002);
|
||||
@@ -1719,13 +1789,6 @@ class ProjectTask extends AbstractModel
|
||||
}
|
||||
}
|
||||
//
|
||||
if ($permission >= 2) {
|
||||
$permission = $task->hasOwner() ? 1 : 0;
|
||||
}
|
||||
if ($permission && !$project->owner && !$task->permission(3)) {
|
||||
throw new ApiException('仅限项目负责人、任务负责人、协助人员或任务创建者操作');
|
||||
}
|
||||
//
|
||||
return $task;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Module\Base;
|
||||
use App\Exceptions\ApiException;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectTaskContent
|
||||
@@ -13,9 +14,15 @@ use App\Module\Base;
|
||||
* @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)
|
||||
@@ -59,6 +66,9 @@ class ProjectTaskContent extends AbstractModel
|
||||
*/
|
||||
public static function saveContent($task_id, $content)
|
||||
{
|
||||
@ini_set("pcre.backtrack_limit", 999999999);
|
||||
//
|
||||
$oldContent = $content;
|
||||
$path = 'uploads/task/content/' . date("Ym") . '/' . $task_id . '/';
|
||||
//
|
||||
preg_match_all("/<img\s+src=\"data:image\/(png|jpg|jpeg|webp);base64,(.*?)\"/s", $content, $matchs);
|
||||
@@ -77,7 +87,10 @@ class ProjectTaskContent extends AbstractModel
|
||||
$filePath = $path . md5($content);
|
||||
$publicPath = public_path($filePath);
|
||||
Base::makeDir(dirname($publicPath));
|
||||
file_put_contents($publicPath, $content);
|
||||
$result = file_put_contents($publicPath, $content);
|
||||
if(!$result && $oldContent){
|
||||
throw new ApiException("保存任务详情至文件失败,请重试");
|
||||
}
|
||||
//
|
||||
return $filePath;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
43
app/Models/ProjectTaskVisibilityUser.php
Normal file
43
app/Models/ProjectTaskVisibilityUser.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectTaskVisibilityUser
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property int|null $task_id 任务ID
|
||||
* @property int|null $userid 成员ID
|
||||
* @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)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskVisibilityUser whereTaskId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskVisibilityUser whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskVisibilityUser whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ProjectTaskVisibilityUser extends AbstractModel
|
||||
{
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function projectTask(): \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
{
|
||||
return $this->hasOne(ProjectTask::class, 'id', 'task_id');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** ***************************************************************************************** */
|
||||
/** ***************************************************************************************** */
|
||||
/** ***************************************************************************************** */
|
||||
@@ -379,7 +405,7 @@ class User extends AbstractModel
|
||||
{
|
||||
$user = self::authInfo();
|
||||
if (!$user) {
|
||||
if (Base::headerOrInput('token')) {
|
||||
if (Base::token()) {
|
||||
throw new ApiException('身份已失效,请重新登录', [], -1);
|
||||
} else {
|
||||
throw new ApiException('请登录后继续...', [], -1);
|
||||
@@ -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提醒',
|
||||
@@ -114,6 +122,16 @@ class UserBot extends AbstractModel
|
||||
'label' => Doo::translate('我的机器人')
|
||||
],
|
||||
],
|
||||
'ai-openai@bot.system',
|
||||
'ai-claude@bot.system',
|
||||
'ai-wenxin@bot.system',
|
||||
'ai-gemini@bot.system',
|
||||
'ai-qianwen@bot.system' => [
|
||||
[
|
||||
'key' => '%3A.clear',
|
||||
'label' => Doo::translate('清空上下文')
|
||||
]
|
||||
],
|
||||
default => [],
|
||||
};
|
||||
|
||||
@@ -218,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)
|
||||
|
||||
@@ -10,6 +10,7 @@ use Cache;
|
||||
use Carbon\Carbon;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* App\Models\WebSocketDialog
|
||||
@@ -19,25 +20,35 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @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()
|
||||
@@ -74,9 +85,9 @@ class WebSocketDialog extends AbstractModel
|
||||
* @param $deleted
|
||||
* @return array
|
||||
*/
|
||||
public function getDialogList($userid, $updated = "", $deleted = "")
|
||||
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) {
|
||||
@@ -84,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);
|
||||
@@ -97,6 +108,74 @@ class WebSocketDialog extends AbstractModel
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 列表外的未读对话 和 列表外的待办对话
|
||||
* @param $userid
|
||||
* @param $unreadAt
|
||||
* @param $todoAt
|
||||
* @return WebSocketDialog[]
|
||||
*/
|
||||
public static function getDialogBeyond($userid, $unreadAt, $todoAt)
|
||||
{
|
||||
DB::statement("SET SQL_MODE=''");
|
||||
$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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 格式化对话
|
||||
* @param int $userid 会员ID
|
||||
@@ -113,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');
|
||||
// 是否免打扰
|
||||
@@ -159,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) {
|
||||
@@ -182,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;
|
||||
@@ -190,10 +279,26 @@ class WebSocketDialog extends AbstractModel
|
||||
if ($hasData === true) {
|
||||
$msgBuilder = WebSocketDialogMsg::whereDialogId($this->id);
|
||||
$this->has_tag = $msgBuilder->clone()->where('tag', '>', 0)->exists();
|
||||
$this->has_todo = $msgBuilder->clone()->where('todo', '>', 0)->exists();
|
||||
$this->has_image = $msgBuilder->clone()->whereMtype('image')->exists();
|
||||
$this->has_file = $msgBuilder->clone()->whereMtype('file')->exists();
|
||||
$this->has_link = $msgBuilder->clone()->whereLink(1)->exists();
|
||||
$this->has_todo = $msgBuilder->clone()->where('todo', '>', 0)->exists();
|
||||
Cache::forever("Dialog::tag:" . $this->id, Base::array2json([
|
||||
'has_tag' => $this->has_tag,
|
||||
'has_todo' => $this->has_todo,
|
||||
'has_image' => $this->has_image,
|
||||
'has_file' => $this->has_file,
|
||||
'has_link' => $this->has_link,
|
||||
]));
|
||||
} else {
|
||||
$tagData = Base::json2array(Cache::get("Dialog::tag:" . $this->id));
|
||||
if ($tagData) {
|
||||
$this->has_tag = !!$tagData['has_tag'];
|
||||
$this->has_todo = !!$tagData['has_todo'];
|
||||
$this->has_image = !!$tagData['has_image'];
|
||||
$this->has_file = !!$tagData['has_file'];
|
||||
$this->has_link = !!$tagData['has_link'];
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
@@ -201,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();
|
||||
@@ -212,12 +336,14 @@ class WebSocketDialog extends AbstractModel
|
||||
if ($positionData) {
|
||||
$array = [];
|
||||
// @我的消息
|
||||
if ($this->mention > 0
|
||||
&& $mention_id = intval($builder->clone()->whereMention(1)->orderByDesc('msg_id')->value('msg_id'))) {
|
||||
$array[] = [
|
||||
'msg_id' => $mention_id,
|
||||
'label' => Doo::translate('@我的消息'),
|
||||
];
|
||||
if ($this->mention > 0) {
|
||||
$list = $builder->clone()->whereMention(1)->orderByDesc('msg_id')->take(20)->get();
|
||||
foreach ($list as $item) {
|
||||
$array[] = [
|
||||
'msg_id' => $item->msg_id,
|
||||
'label' => Doo::translate('@我的消息'),
|
||||
];
|
||||
}
|
||||
}
|
||||
// 最早一条未读消息
|
||||
if ($this->unread > 0
|
||||
@@ -384,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -452,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
|
||||
@@ -500,6 +632,7 @@ class WebSocketDialog extends AbstractModel
|
||||
return $dialog;
|
||||
}
|
||||
if (!WebSocketDialogUser::whereDialogId($dialog->id)->whereUserid($userid)->exists()) {
|
||||
WebSocketDialogMsgRead::forceRead($dialog_id, $userid);
|
||||
throw new ApiException('不在成员列表内', ['dialog_id' => $dialog_id], -4003);
|
||||
}
|
||||
return $dialog;
|
||||
@@ -521,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) {
|
||||
@@ -529,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();
|
||||
}
|
||||
}
|
||||
@@ -558,7 +691,7 @@ class WebSocketDialog extends AbstractModel
|
||||
if ($dialogUser) {
|
||||
return $dialogUser;
|
||||
}
|
||||
if ($receiver > 0 && $user->isTemp()) {
|
||||
if ($receiver > 0 && $user->isTemp() && !User::whereUserid($receiver)->whereBot(1)->exists() ) {
|
||||
throw new ApiException('无法发起会话,请联系管理员。');
|
||||
}
|
||||
return AbstractModel::transaction(function () use ($receiver, $user) {
|
||||
@@ -609,11 +742,13 @@ class WebSocketDialog extends AbstractModel
|
||||
Base::makeDir(public_path($path));
|
||||
copy($filePath, public_path($path) . basename($filePath));
|
||||
} else {
|
||||
$setting = Base::setting('system');
|
||||
$data = Base::upload([
|
||||
"file" => $files,
|
||||
"type" => 'more',
|
||||
"path" => $path,
|
||||
"fileName" => $fileName,
|
||||
"size" => ($setting['file_upload_limit'] ?: 0) * 1024
|
||||
]);
|
||||
}
|
||||
//
|
||||
|
||||
@@ -31,21 +31,30 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property int|null $modify 是否编辑
|
||||
* @property int|null $reply_num 有多少条回复
|
||||
* @property int|null $reply_id 回复ID
|
||||
* @property int|null $forward_id 转发ID
|
||||
* @property int|null $forward_num 被转发多少次
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @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)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereDialogType($value)
|
||||
* @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 whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereKey($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereLink($value)
|
||||
@@ -71,7 +80,6 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
|
||||
protected $appends = [
|
||||
'percentage',
|
||||
'reply_data',
|
||||
];
|
||||
|
||||
protected $hidden = [
|
||||
@@ -99,21 +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'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息格式化
|
||||
* @param $value
|
||||
@@ -124,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;
|
||||
}
|
||||
@@ -148,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 是否新增阅读数
|
||||
@@ -368,13 +378,25 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
* 转发消息
|
||||
* @param array|int $dialogids
|
||||
* @param array|int $userids
|
||||
* @param User $user 发送的会员
|
||||
* @param User $user 发送的会员
|
||||
* @param int $showSource 是否显示原发送者信息
|
||||
* @param string $leaveMessage 转发留言
|
||||
* @return mixed
|
||||
*/
|
||||
public function forwardMsg($dialogids, $userids, $user)
|
||||
public function forwardMsg($dialogids, $userids, $user, $showSource = 1, $leaveMessage = '')
|
||||
{
|
||||
return AbstractModel::transaction(function() use ($dialogids, $user, $userids) {
|
||||
$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) {
|
||||
@@ -382,11 +404,14 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
$dialogids = [$dialogids];
|
||||
}
|
||||
foreach ($dialogids as $dialogid) {
|
||||
$res = self::sendMsg(null, $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;
|
||||
}
|
||||
if ($leaveMessage) {
|
||||
self::sendMsg(null, $dialogid, 'text', ['text' => $leaveMessage], $user->userid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($userids) {
|
||||
@@ -399,13 +424,19 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
}
|
||||
$dialog = WebSocketDialog::checkUserDialog($user, $userid);
|
||||
if ($dialog && !in_array($dialog->id, $already)) {
|
||||
$res = self::sendMsg(null, $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'];
|
||||
}
|
||||
if ($leaveMessage) {
|
||||
self::sendMsg(null, $dialog->id, 'text', ['text' => $leaveMessage], $user->userid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($msgs) > 0) {
|
||||
$this->increment('forward_num', count($msgs));
|
||||
}
|
||||
return Base::retSuccess('转发成功', [
|
||||
'msgs' => $msgs
|
||||
]);
|
||||
@@ -427,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()]);
|
||||
@@ -470,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
|
||||
],
|
||||
]
|
||||
@@ -497,6 +527,8 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
}
|
||||
switch ($data['type']) {
|
||||
case 'text':
|
||||
case 'word-chain':
|
||||
case 'vote':
|
||||
return $this->previewTextMsg($data['msg']['text'], $preserveHtml);
|
||||
case 'record':
|
||||
return "[语音]";
|
||||
@@ -510,6 +542,9 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
case 'tag':
|
||||
$action = $data['msg']['action'] === 'remove' ? '取消标注' : '标注';
|
||||
return "[{$action}] {$this->previewMsg(false, $data['msg']['data'])}";
|
||||
case 'top':
|
||||
$action = $data['msg']['action'] === 'remove' ? '取消置顶' : '置顶';
|
||||
return "[{$action}] {$this->previewMsg(false, $data['msg']['data'])}";
|
||||
case 'todo':
|
||||
$action = $data['msg']['action'] === 'remove' ? '取消待办' : ($data['msg']['action'] === 'done' ? '完成' : '设待办');
|
||||
return "[{$action}] {$this->previewMsg(false, $data['msg']['data'])}";
|
||||
@@ -684,7 +719,7 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
foreach ($matchs[1] as $key => $str) {
|
||||
preg_match("/data-denotation-char=\"(.*?)\"/", $str, $matchChar);
|
||||
preg_match("/data-id=\"(.*?)\"/", $str, $matchId);
|
||||
preg_match("/data-value=\"(.*?)\"/", $str, $matchValye);
|
||||
preg_match("/data-value=\"(.*?)\"/s", $str, $matchValye);
|
||||
$keyId = $matchId[1];
|
||||
if ($matchChar[1] === "~") {
|
||||
if (Base::isNumber($keyId)) {
|
||||
@@ -750,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);
|
||||
@@ -760,7 +808,7 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
return "<img class=\"{$match[1]}\"{$wh} src=\"{$src}\" alt=\"{$match[5]}\"/>";
|
||||
}, $text);
|
||||
$text = preg_replace("/\[:@:(.*?):(.*?):\]/i", "<span class=\"mention user\" data-id=\"$1\">@$2</span>", $text);
|
||||
$text = preg_replace("/\[:#:(.*?):(.*?):\]/i", "<span class=\"mention task\" data-id=\"$1\">#$2</span>", $text);
|
||||
$text = preg_replace("/\[:#:(.*?):(.*?):\]/is", "<span class=\"mention task\" data-id=\"$1\">#$2</span>", $text);
|
||||
$text = preg_replace("/\[:~:(.*?):(.*?):\]/i", "<a class=\"mention file\" href=\"{{RemoteURL}}single/file/$1\" target=\"_blank\">~$2</a>", $text);
|
||||
$text = preg_replace("/\[:QUICK:(.*?):(.*?):\]/i", "<span data-quick-key=\"$1\">$2</span>", $text);
|
||||
return preg_replace("/^(<p><\/p>)+|(<p><\/p>)+$/i", "", $text);
|
||||
@@ -772,6 +820,7 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
* - reply-98:回复消息ID=98
|
||||
* - update-99:更新消息ID=99(标记修改)
|
||||
* - change-99:更新消息ID=99(不标记修改)
|
||||
* - forward-99:转发消息ID=99
|
||||
* @param int $dialog_id 会话ID(即 聊天室ID)
|
||||
* @param string $type 消息类型
|
||||
* @param array $msg 发送的消息
|
||||
@@ -809,9 +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;
|
||||
$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);
|
||||
@@ -833,23 +883,37 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
if (empty($dialogMsg)) {
|
||||
throw new ApiException('消息不存在');
|
||||
}
|
||||
if ($dialogMsg->type !== 'text') {
|
||||
throw new ApiException('此消息不支持此操作');
|
||||
}
|
||||
if ($dialogMsg->userid != $sender) {
|
||||
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, [
|
||||
@@ -859,14 +923,28 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
return Base::retSuccess('修改成功', $dialogMsg);
|
||||
} else {
|
||||
// 发送
|
||||
if ($reply_id && !self::whereId($reply_id)->increment('reply_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,
|
||||
@@ -874,13 +952,24 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
'msg' => $msg,
|
||||
'read' => 0,
|
||||
]);
|
||||
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)
|
||||
@@ -47,6 +53,20 @@ class WebSocketDialogMsgRead extends AbstractModel
|
||||
return $this->hasOne(WebSocketDialogMsg::class, 'id', 'msg_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制标记成阅读
|
||||
* @param $dialogId
|
||||
* @param $userId
|
||||
* @return void
|
||||
*/
|
||||
public static function forceRead($dialogId, $userId)
|
||||
{
|
||||
self::whereDialogId($dialogId)
|
||||
->whereUserid($userId)
|
||||
->whereNull('read_at')
|
||||
->update(['read_at' => Carbon::now()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅标记成阅读
|
||||
* @param $list
|
||||
|
||||
@@ -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,21 +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 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)
|
||||
@@ -44,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)
|
||||
|
||||
@@ -11,6 +11,8 @@ use Redirect;
|
||||
use Request;
|
||||
use Response;
|
||||
use Storage;
|
||||
use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
use Validator;
|
||||
|
||||
class Base
|
||||
@@ -75,6 +77,15 @@ class Base
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function token()
|
||||
{
|
||||
return Base::headerOrInput('dootask-token') ?: Base::headerOrInput('token');
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果header没有则通过input读取
|
||||
* @param $key
|
||||
@@ -122,7 +133,8 @@ class Base
|
||||
|
||||
/**
|
||||
* 判断客户端版本
|
||||
* @param $min
|
||||
* @param $min // 最小版本(满足此版本返回true)
|
||||
* @param null $clientVersion
|
||||
* @return bool
|
||||
*/
|
||||
public static function judgeClientVersion($min, $clientVersion = null)
|
||||
@@ -676,6 +688,22 @@ class Base
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归处理数组
|
||||
*
|
||||
* @param string $callback 如:'intval'、'trim'、'addslashes'、'stripslashes'、'htmlspecialchars'
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
public static function newArrayRecursive($callback, $array)
|
||||
{
|
||||
$func = function ($item) use (&$func, &$callback) {
|
||||
return is_array($item) ? array_map($func, $item) : call_user_func($callback, $item);
|
||||
};
|
||||
|
||||
return array_map($func, $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重MD5加密
|
||||
* @param $text
|
||||
@@ -2090,7 +2118,7 @@ class Base
|
||||
}
|
||||
$scaleName = "";
|
||||
if ($param['fileName']) {
|
||||
$fileName = $param['fileName'];
|
||||
$fileName = basename($param['fileName']);
|
||||
} else {
|
||||
if ($param['scale'] && is_array($param['scale'])) {
|
||||
list($width, $height) = $param['scale'];
|
||||
@@ -2249,7 +2277,7 @@ class Base
|
||||
if ($param['fileName'] === true) {
|
||||
$fileName = $file->getClientOriginalName();
|
||||
} elseif ($param['fileName']) {
|
||||
$fileName = $param['fileName'];
|
||||
$fileName = basename($param['fileName']);
|
||||
} else {
|
||||
if ($param['scale'] && is_array($param['scale'])) {
|
||||
list($width, $height) = $param['scale'];
|
||||
@@ -2445,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';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2870,15 +2903,40 @@ class Base
|
||||
|
||||
/**
|
||||
* 流下载,解决没有后缀无法下载的问题
|
||||
* @param $callback
|
||||
* @param $file
|
||||
* @param $name
|
||||
* @return mixed
|
||||
*/
|
||||
public static function streamDownload($callback, $name = null) {
|
||||
public static function streamDownload($file, $name = null)
|
||||
{
|
||||
$contentType = 'application/octet-stream';
|
||||
if ($name && !str_contains($name, '.')) {
|
||||
$name .= ".";
|
||||
}
|
||||
return Response::streamDownload($callback, $name);
|
||||
//
|
||||
if ($file instanceof \Closure) {
|
||||
return Response::streamDownload($file, $name, [
|
||||
'Content-Type' => $contentType,
|
||||
]);
|
||||
}
|
||||
//
|
||||
if (!$file instanceof File) {
|
||||
if ($file instanceof \SplFileInfo) {
|
||||
$file = new File($file->getPathname());
|
||||
} else {
|
||||
$file = new File((string)$file);
|
||||
}
|
||||
}
|
||||
if (!$file->isReadable()) {
|
||||
throw new FileException('File must be readable.');
|
||||
}
|
||||
$contentType = $file->getMimeType() ?: $contentType;
|
||||
$content = $file->getContent();
|
||||
return Response::streamDownload(function() use ($content) {
|
||||
echo $content;
|
||||
}, $name, [
|
||||
'Content-Type' => $contentType,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2936,4 +2994,5 @@ class Base
|
||||
}
|
||||
return $newArray;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ class Doo
|
||||
char* pgpEncrypt(char* plainText, char* publicKey);
|
||||
char* pgpDecrypt(char* cipherText, char* privateKey, char* passphrase);
|
||||
EOF, "/usr/lib/doo/doo.so");
|
||||
$token = $token ?: Base::headerOrInput('token');
|
||||
$token = $token ?: Base::token();
|
||||
$language = $language ?: Base::headerOrInput('language');
|
||||
self::$doo->initialize("/var/www", $token, $language);
|
||||
}
|
||||
@@ -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,
|
||||
],
|
||||
]));
|
||||
// 通知上线
|
||||
@@ -172,8 +173,11 @@ class WebSocketService implements WebSocketHandlerInterface
|
||||
*/
|
||||
public function onClose(Server $server, $fd, $reactorId)
|
||||
{
|
||||
Task::deliver(new LineTask($this->getUserid($fd), false)); // 通知离线
|
||||
$this->deleteUser($fd);
|
||||
$userid = $this->getUserid($fd);
|
||||
if($userid){
|
||||
Task::deliver(new LineTask($userid, false)); // 通知离线
|
||||
$this->deleteUser($fd);
|
||||
}
|
||||
}
|
||||
|
||||
/** ****************************************************************************** */
|
||||
|
||||
@@ -71,6 +71,9 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
}
|
||||
if (preg_match("/<span[^>]*?data-quick-key=([\"'])(.*?)\\1[^>]*?>(.*?)<\/span>/is", $original, $match)) {
|
||||
$command = $match[2];
|
||||
if (str_starts_with($command, '%3A.')) {
|
||||
$command = ":" . substr($command, 4);
|
||||
}
|
||||
} else {
|
||||
$command = trim(strip_tags($original));
|
||||
}
|
||||
@@ -313,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()) {
|
||||
@@ -375,7 +378,9 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
$extras = [
|
||||
'openai_key' => $setting['openai_key'],
|
||||
'openai_agency' => $setting['openai_agency'],
|
||||
'openai_model' => $setting['openai_model'],
|
||||
'server_url' => $serverUrl,
|
||||
'chunk_size' => 7,
|
||||
];
|
||||
if (empty($extras['openai_key'])) {
|
||||
$error = 'Robot disabled.';
|
||||
@@ -433,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();
|
||||
@@ -448,7 +471,7 @@ class BotReceiveMsgTask extends AbstractTask
|
||||
}
|
||||
//
|
||||
try {
|
||||
$res = Ihttp::ihttp_post($webhookUrl, [
|
||||
$data = [
|
||||
'text' => $command,
|
||||
'token' => User::generateToken($botUser),
|
||||
'dialog_id' => $dialog->id,
|
||||
@@ -459,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;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use App\Models\TaskWorker;
|
||||
use App\Models\Tmp;
|
||||
use App\Models\WebSocketTmpMsg;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\File as SupportFile;
|
||||
|
||||
/**
|
||||
* 删除过期临时数据任务
|
||||
@@ -96,6 +97,28 @@ class DeleteTmpTask extends AbstractTask
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
/**
|
||||
* file_pack 临时压缩下载文件
|
||||
*/
|
||||
case 'file_pack':
|
||||
{
|
||||
$path = public_path('tmp/file/');
|
||||
if (!SupportFile::exists($path)) {
|
||||
return;
|
||||
}
|
||||
$dirIterator = new \RecursiveDirectoryIterator($path);
|
||||
$iterator = new \RecursiveIteratorIterator($dirIterator);
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isFile()) {
|
||||
$time = $file->getMTime();
|
||||
if ($time < time() - 3600 * 24) {
|
||||
unlink($file->getPathname());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
87
app/Tasks/UnclaimedTaskRemindTask.php
Normal file
87
app/Tasks/UnclaimedTaskRemindTask.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tasks;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Module\Base;
|
||||
use App\Models\Project;
|
||||
use App\Models\ProjectTask;
|
||||
use App\Models\ProjectUser;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\WebSocketDialogMsg;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
|
||||
|
||||
class UnclaimedTaskRemindTask extends AbstractTask
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
//
|
||||
$setting = Base::setting('system');
|
||||
if ($setting['unclaimed_task_reminder'] !== 'open') {
|
||||
return;
|
||||
}
|
||||
if (!$setting['unclaimed_task_reminder_time']) {
|
||||
return;
|
||||
}
|
||||
//
|
||||
$times = explode(':', date('H:i'));
|
||||
$reminderTimes = explode(':', $setting['unclaimed_task_reminder_time']);
|
||||
if (!isset($times[1]) || !isset($reminderTimes[1]) || $times[0] != $reminderTimes[0]) {
|
||||
return;
|
||||
}
|
||||
// 执行一次
|
||||
if (Cache::get("UnclaimedTaskRemindTask:His", 0)) {
|
||||
return;
|
||||
}
|
||||
if ($times[1] >= intval($reminderTimes[1]) - 1 && $times[1] <= intval($reminderTimes[1]) + 1) {
|
||||
//
|
||||
Cache::put("UnclaimedTaskRemindTask:His", date('H:i:s'), Carbon::now()->addMinutes(5));
|
||||
//
|
||||
Project::whereNull('deleted_at')->whereNull('archived_at')->chunk(100, function ($projects) {
|
||||
foreach ($projects as $project) {
|
||||
//
|
||||
$projectTasks = ProjectTask::select('project_tasks.id', 'project_tasks.name')
|
||||
->leftJoin('project_task_users', function ($query) {
|
||||
$query->on('project_tasks.id', '=', 'project_task_users.task_id');
|
||||
})
|
||||
->where('project_tasks.project_id', $project->id)
|
||||
->whereNull('project_tasks.deleted_at')
|
||||
->whereNull('project_tasks.archived_at')
|
||||
->whereNull('project_task_users.id')
|
||||
->limit(10)
|
||||
->get();
|
||||
//
|
||||
if (!$projectTasks->isEmpty()) {
|
||||
$botUser = User::botGetOrCreate('task-alert');
|
||||
if (empty($botUser)) {
|
||||
return;
|
||||
}
|
||||
if (!ProjectUser::whereUserid($botUser->userid)->whereProjectId($project->id)->exists()) {
|
||||
$project->joinProject($botUser->userid);
|
||||
$project->syncDialogUser();
|
||||
}
|
||||
//
|
||||
$taskHtml = '<span style="line-height: 26px;">任务待领取</span> <br/>';
|
||||
foreach ($projectTasks as $projectTask) {
|
||||
$taskHtml .= "<span class=\"mention task\" style=\"line-height: 26px;\" data-id=\"{$projectTask->id}\">#{$projectTask->name}</span> <br/>";
|
||||
}
|
||||
WebSocketDialogMsg::sendMsg(null, $project->dialog_id, 'text', [
|
||||
'text' => $taskHtml
|
||||
], $botUser->userid);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function end()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -38,12 +38,17 @@ class WebSocketDialogMsgTask extends AbstractTask
|
||||
{
|
||||
parent::__construct(...func_get_args());
|
||||
$this->id = $id;
|
||||
$this->ignoreFd = $ignoreFd === null ? Request::header('fd') : $ignoreFd;
|
||||
$this->client = [
|
||||
'version' => Base::headerOrInput('version'),
|
||||
'language' => Base::headerOrInput('language'),
|
||||
'platform' => Base::headerOrInput('platform'),
|
||||
];
|
||||
// 判断是否有Request方法,兼容go协程请求
|
||||
$this->ignoreFd = $ignoreFd;
|
||||
$this->client = [];
|
||||
if (method_exists(request(), "header")) {
|
||||
$this->ignoreFd = $ignoreFd === null ? Request::header('fd') : $ignoreFd;
|
||||
$this->client = [
|
||||
'version' => Base::headerOrInput('version'),
|
||||
'language' => Base::headerOrInput('language'),
|
||||
'platform' => Base::headerOrInput('platform'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
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 {
|
||||
159
cmd
159
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,23 @@ 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" == "npm" ]]; then
|
||||
shift 1
|
||||
npm $@
|
||||
cd electron
|
||||
npm $@
|
||||
cd ..
|
||||
docker run --rm -it -v ${cur_path}/resources/mobile:/work -w /work --entrypoint=/bin/bash node:16 -c "npm $@"
|
||||
elif [[ "$1" == "doc" ]]; then
|
||||
shift 1
|
||||
run_exec php "php app/Http/Controllers/Api/apidoc.php"
|
||||
@@ -398,13 +489,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
|
||||
@@ -421,9 +514,9 @@ if [ $# -gt 0 ]; then
|
||||
e="redis $@" && run_exec redis "$e"
|
||||
elif [[ "$1" == "mysql" ]]; then
|
||||
shift 1
|
||||
if [ "$1" = "backup" ]; then
|
||||
if [[ "$1" == "backup" ]] || [[ "$1" == "b" ]]; then
|
||||
run_mysql backup
|
||||
elif [ "$1" = "recovery" ]; then
|
||||
elif [[ "$1" == "recovery" ]] || [[ "$1" == "r" ]]; then
|
||||
run_mysql recovery
|
||||
else
|
||||
e="mysql $@" && run_exec mariadb "$e"
|
||||
|
||||
@@ -11,13 +11,15 @@
|
||||
"php": "^8.0",
|
||||
"ext-curl": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-imagick": "*",
|
||||
"ext-json": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-imagick": "*",
|
||||
"ext-zip": "*",
|
||||
"directorytree/ldaprecord-laravel": "^2.7",
|
||||
"fideloper/proxy": "^4.4.1",
|
||||
"firebase/php-jwt": "^6.9",
|
||||
"fruitcake/laravel-cors": "^2.0.4",
|
||||
"guanguans/notify": "^1.21.1",
|
||||
"guzzlehttp/guzzle": "^7.3.0",
|
||||
|
||||
1506
composer.lock
generated
1506
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -306,7 +306,7 @@ return [
|
||||
'reload_async' => true,
|
||||
'max_wait_time' => 60,
|
||||
'enable_reuse_port' => true,
|
||||
'enable_coroutine' => false,
|
||||
'enable_coroutine' => true,
|
||||
'upload_tmp_dir' => @is_writable('/dev/shm/') ? '/dev/shm' : '/tmp',
|
||||
'http_compression' => false,
|
||||
],
|
||||
|
||||
@@ -30,7 +30,7 @@ class AddProjectTasksIsAllVisible extends Migration
|
||||
{
|
||||
//
|
||||
Schema::table('project_tasks', function (Blueprint $table) {
|
||||
$table->dropColumn("avatar");
|
||||
$table->dropColumn("is_all_visible");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class RenameProjectTasksIsAllVisible extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('project_tasks', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('project_tasks', 'is_all_visible')) {
|
||||
$pre = DB::connection()->getTablePrefix();
|
||||
DB::statement("ALTER TABLE `{$pre}project_tasks` MODIFY COLUMN is_all_visible TINYINT(1) DEFAULT 1 COMMENT '任务可见性:1-项目人员 2-任务人员 3-指定成员'");
|
||||
$table->renameColumn('is_all_visible', 'visibility');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateProjectPermissionsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if (Schema::hasTable('project_permissions'))
|
||||
return;
|
||||
|
||||
Schema::create('project_permissions', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('project_id')->nullable()->default(0)->comment('项目ID');
|
||||
$table->text('permissions')->nullable()->comment('权限');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('project_permissions');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class WebSocketDialogMsgsAddForwardId 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_id')) {
|
||||
$table->bigInteger('forward_id')->nullable()->default(0)->after('reply_id')->comment('转发ID');
|
||||
$table->bigInteger('forward_num')->nullable()->default(0)->after('forward_id')->comment('被转发多少次');
|
||||
$table->boolean('forward_show')->nullable()->default(1)->after('forward_num')->comment('是否显示转发的来源');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
|
||||
$table->dropColumn("forward_id");
|
||||
$table->dropColumn("forward_num");
|
||||
$table->dropColumn("forward_show");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddIndexSome20231217 extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('project_task_users', function (Blueprint $table) {
|
||||
$table->index('task_id');
|
||||
$table->index('task_pid');
|
||||
});
|
||||
Schema::table('project_tasks', function (Blueprint $table) {
|
||||
$table->index('visibility');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return voidw
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('project_task_users', function (Blueprint $table) {
|
||||
$table->dropIndex(['task_id']);
|
||||
$table->dropIndex(['task_pid']);
|
||||
});
|
||||
Schema::table('project_tasks', function (Blueprint $table) {
|
||||
$table->dropIndex(['visibility']);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class UpdateOwnerAddIndexSome20231217 extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// 项目相关
|
||||
Schema::table('projects', function (Blueprint $table) {
|
||||
$table->index('userid');
|
||||
$table->index('dialog_id');
|
||||
});
|
||||
Schema::table('project_users', function (Blueprint $table) {
|
||||
$table->index('userid');
|
||||
$table->index('project_id');
|
||||
$table->index(['project_id','userid']);
|
||||
$table->index('owner');
|
||||
$table->integer('owner')->change();
|
||||
});
|
||||
Schema::table('project_tasks', function (Blueprint $table) {
|
||||
$table->index('parent_id');
|
||||
$table->index('dialog_id');
|
||||
$table->index('userid');
|
||||
$table->integer('visibility')->change();
|
||||
});
|
||||
Schema::table('project_task_users', function (Blueprint $table) {
|
||||
$table->index(['task_id','userid']);
|
||||
$table->index('owner');
|
||||
$table->integer('owner')->change();
|
||||
});
|
||||
Schema::table('project_task_files', function (Blueprint $table) {
|
||||
$table->index('project_id');
|
||||
$table->index('task_id');
|
||||
});
|
||||
Schema::table('project_task_tags', function (Blueprint $table) {
|
||||
$table->index('project_id');
|
||||
$table->index('task_id');
|
||||
});
|
||||
Schema::table('project_task_contents', function (Blueprint $table) {
|
||||
$table->index('project_id');
|
||||
$table->index('task_id');
|
||||
});
|
||||
Schema::table('project_task_push_logs', function (Blueprint $table) {
|
||||
$table->index('userid');
|
||||
$table->index('task_id');
|
||||
});
|
||||
Schema::table('project_task_flow_changes', function (Blueprint $table) {
|
||||
$table->index('userid');
|
||||
$table->index('task_id');
|
||||
});
|
||||
|
||||
// 聊天相关
|
||||
Schema::table('web_socket_dialogs', function (Blueprint $table) {
|
||||
$table->index('owner_id');
|
||||
$table->index('link_id');
|
||||
});
|
||||
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
|
||||
$table->integer('link')->change();
|
||||
$table->integer('modify')->change();
|
||||
$table->integer('forward_show')->change();
|
||||
});
|
||||
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
|
||||
$table->index('dialog_id');
|
||||
$table->index('userid');
|
||||
$table->integer('mark_unread')->change();
|
||||
$table->integer('silence')->change();
|
||||
$table->integer('important')->change();
|
||||
});
|
||||
Schema::table('web_socket_dialog_msg_todos', function (Blueprint $table) {
|
||||
$table->index('msg_id');
|
||||
$table->index('userid');
|
||||
});
|
||||
Schema::table('web_socket_dialog_msg_reads', function (Blueprint $table) {
|
||||
$table->index('dialog_id');
|
||||
$table->integer('mention')->change();
|
||||
$table->integer('silence')->change();
|
||||
$table->integer('email')->change();
|
||||
$table->integer('after')->change();
|
||||
});
|
||||
|
||||
// 文件相关
|
||||
Schema::table('files', function (Blueprint $table) {
|
||||
$table->index('pid');
|
||||
$table->index('cid');
|
||||
$table->integer('share')->change();
|
||||
});
|
||||
Schema::table('file_users', function (Blueprint $table) {
|
||||
$table->index('file_id');
|
||||
$table->index('userid');
|
||||
$table->integer('permission')->change();
|
||||
});
|
||||
Schema::table('file_links', function (Blueprint $table) {
|
||||
$table->index('file_id');
|
||||
$table->index('userid');
|
||||
});
|
||||
Schema::table('file_contents', function (Blueprint $table) {
|
||||
$table->index('fid');
|
||||
$table->index('userid');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return voidw
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// 项目相关
|
||||
Schema::table('projects', function (Blueprint $table) {
|
||||
$table->dropIndex(['userid']);
|
||||
$table->dropIndex(['dialog_id']);
|
||||
});
|
||||
Schema::table('project_users', function (Blueprint $table) {
|
||||
$table->dropIndex(['userid']);
|
||||
$table->dropIndex(['project_id']);
|
||||
$table->dropIndex(['owner']);
|
||||
$table->dropIndex(['project_id','userid']);
|
||||
});
|
||||
Schema::table('project_tasks', function (Blueprint $table) {
|
||||
$table->dropIndex(['parent_id']);
|
||||
$table->dropIndex(['dialog_id']);
|
||||
$table->dropIndex(['userid']);
|
||||
});
|
||||
Schema::table('project_task_users', function (Blueprint $table) {
|
||||
$table->dropIndex(['owner']);
|
||||
$table->dropIndex(['task_id','userid']);
|
||||
});
|
||||
Schema::table('project_task_files', function (Blueprint $table) {
|
||||
$table->dropIndex(['project_id']);
|
||||
$table->dropIndex(['task_id']);
|
||||
});
|
||||
Schema::table('project_task_tags', function (Blueprint $table) {
|
||||
$table->dropIndex(['project_id']);
|
||||
$table->dropIndex(['task_id']);
|
||||
});
|
||||
Schema::table('project_task_contents', function (Blueprint $table) {
|
||||
$table->dropIndex(['project_id']);
|
||||
$table->dropIndex(['task_id']);
|
||||
});
|
||||
Schema::table('project_task_push_logs', function (Blueprint $table) {
|
||||
$table->dropIndex(['userid']);
|
||||
$table->dropIndex(['task_id']);
|
||||
});
|
||||
Schema::table('project_task_flow_changes', function (Blueprint $table) {
|
||||
$table->dropIndex(['userid']);
|
||||
$table->dropIndex(['task_id']);
|
||||
});
|
||||
|
||||
// 聊天相关
|
||||
Schema::table('web_socket_dialogs', function (Blueprint $table) {
|
||||
$table->dropIndex(['owner_id']);
|
||||
$table->dropIndex(['link_id']);
|
||||
});
|
||||
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
|
||||
$table->dropIndex(['dialog_id']);
|
||||
$table->dropIndex(['userid']);
|
||||
});
|
||||
Schema::table('web_socket_dialog_msg_todos', function (Blueprint $table) {
|
||||
$table->dropIndex(['msg_id']);
|
||||
$table->dropIndex(['userid']);
|
||||
});
|
||||
Schema::table('web_socket_dialog_msg_reads', function (Blueprint $table) {
|
||||
$table->dropIndex(['dialog_id']);
|
||||
});
|
||||
|
||||
// 文件相关
|
||||
Schema::table('files', function (Blueprint $table) {
|
||||
$table->dropIndex(['pid']);
|
||||
$table->dropIndex(['cid']);
|
||||
});
|
||||
Schema::table('file_users', function (Blueprint $table) {
|
||||
$table->dropIndex(['file_id']);
|
||||
$table->dropIndex(['userid']);
|
||||
});
|
||||
Schema::table('file_links', function (Blueprint $table) {
|
||||
$table->dropIndex(['file_id']);
|
||||
$table->dropIndex(['userid']);
|
||||
});
|
||||
Schema::table('file_contents', function (Blueprint $table) {
|
||||
$table->dropIndex(['fid']);
|
||||
$table->dropIndex(['userid']);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddWebSocketDialogMsgsTopAt 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', 'top')) {
|
||||
$table->bigInteger('top')->nullable()->default(0)->after('send')->comment('置顶的会员ID');
|
||||
$table->timestamp('top_at')->nullable()->after('top')->comment('置顶时间');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
|
||||
$table->dropColumn("top");
|
||||
$table->dropColumn("top_at");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateProjectTaskVisibilityUsersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('project_task_visibility_users', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('project_id')->index()->nullable()->default(0)->comment('项目ID');
|
||||
$table->bigInteger('task_id')->index()->nullable()->default(0)->comment('任务ID');
|
||||
$table->bigInteger('userid')->index()->nullable()->default(0)->comment('成员ID');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
// 迁移旧数据
|
||||
DB::table('project_task_users')->where("owner",2)->orderBy('id')->chunk(100, function ($data) {
|
||||
foreach ($data as $item) {
|
||||
DB::table('project_task_visibility_users')->insert([
|
||||
'project_id' => $item->project_id,
|
||||
'task_id' => $item->task_id,
|
||||
'userid' => $item->userid,
|
||||
'created_at' => $item->created_at,
|
||||
'updated_at' => $item->updated_at
|
||||
]);
|
||||
}
|
||||
});
|
||||
DB::table('project_task_users')->where("owner",2)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('project_task_visibility_users');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddWebSocketDialogsTop 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', 'top')) {
|
||||
$table->dropColumn("top");
|
||||
$table->dropColumn("top_at");
|
||||
}
|
||||
});
|
||||
//
|
||||
Schema::table('web_socket_dialogs', function (Blueprint $table) {
|
||||
$table->bigInteger('top_userid')->nullable()->default(0)->after('link_id')->comment('置顶的用户ID');
|
||||
$table->bigInteger('top_msg_id')->nullable()->default(0)->after('top_userid')->comment('置顶的消息ID');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('web_socket_dialog_msgs', 'top')) {
|
||||
$table->bigInteger('top')->nullable()->default(0)->after('send')->comment('置顶的会员ID');
|
||||
$table->timestamp('top_at')->nullable()->after('top')->comment('置顶时间');
|
||||
}
|
||||
});
|
||||
//
|
||||
Schema::table('web_socket_dialogs', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('web_socket_dialogs', 'top_msg_id')) {
|
||||
$table->dropColumn("top_msg_id");
|
||||
}
|
||||
if (Schema::hasColumn('web_socket_dialogs', 'top_userid')) {
|
||||
$table->dropColumn("top_userid");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
// 回滚数据 - 无法回滚
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user