Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
470772341f | ||
|
|
675f00b8a0 | ||
|
|
ae52803aec | ||
|
|
fb8cf78958 |
@@ -1,4 +1,4 @@
|
||||
APP_NAME=DooTask
|
||||
APP_NAME=Dootask
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
|
||||
85
.github/workflows/electron-generic.yml
vendored
85
.github/workflows/electron-generic.yml
vendored
@@ -1,85 +0,0 @@
|
||||
name: Build Generic
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build-mac:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
id: [ "com.dootask.task", "com.hitosea.task" ]
|
||||
runs-on: macos-latest
|
||||
environment: build
|
||||
|
||||
if: startsWith(github.event.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Create changelog text
|
||||
id: changelog
|
||||
uses: loopwerk/tag-changelog@v1
|
||||
with:
|
||||
token: ${{ secrets.GH_PAT }}
|
||||
exclude_types: other,chore,build
|
||||
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Build for MacOS
|
||||
env:
|
||||
APPID: ${{ matrix.id }}
|
||||
PROVIDER: "generic"
|
||||
APPLEID: ${{ secrets.APPLEID }}
|
||||
APPLEIDPASS: ${{ secrets.APPLEIDPASS }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
||||
CSC_LINK: ${{ secrets.CSC_LINK }}
|
||||
RELEASE_BODY: ${{ steps.changelog.outputs.changes }}
|
||||
run: ./cmd electron build-mac
|
||||
|
||||
build-win:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
id: [ "com.dootask.task", "com.hitosea.task" ]
|
||||
runs-on: windows-latest
|
||||
environment: build
|
||||
|
||||
if: startsWith(github.event.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Create changelog text
|
||||
id: changelog
|
||||
uses: loopwerk/tag-changelog@v1
|
||||
with:
|
||||
token: ${{ secrets.GH_PAT }}
|
||||
exclude_types: other,chore,build
|
||||
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Build for Windows
|
||||
shell: powershell
|
||||
env:
|
||||
APPID: ${{ matrix.id }}
|
||||
PROVIDER: "generic"
|
||||
RELEASE_BODY: ${{ steps.changelog.outputs.changes }}
|
||||
run: |
|
||||
npm install
|
||||
cd electron
|
||||
npm install
|
||||
cd ../
|
||||
mkdir -p ./electron/public
|
||||
cp ./electron/index.html ./electron/public/index.html
|
||||
npx mix --production -- --env --electron
|
||||
node ./electron/build.js build-win
|
||||
|
||||
97
.github/workflows/electron-github.yml
vendored
97
.github/workflows/electron-github.yml
vendored
@@ -1,97 +0,0 @@
|
||||
name: Build Github
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: ${{ (startsWith(github.event.ref, 'refs/tags/v')) && (github.repository == 'kuaifan/dootask') }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Create changelog text
|
||||
id: changelog
|
||||
uses: loopwerk/tag-changelog@v1
|
||||
with:
|
||||
token: ${{ secrets.GH_PAT }}
|
||||
exclude_types: other,chore,build
|
||||
|
||||
- name: Create release
|
||||
uses: actions/create-release@latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
body: ${{ steps.changelog.outputs.changes }}
|
||||
|
||||
build-mac:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
id: [ "com.dootask.task", "com.hitosea.task" ]
|
||||
runs-on: macos-latest
|
||||
environment: build
|
||||
|
||||
if: ${{ (startsWith(github.event.ref, 'refs/tags/v')) && (github.repository == 'kuaifan/dootask') }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Build for MacOS
|
||||
env:
|
||||
APPID: ${{ matrix.id }}
|
||||
PROVIDER: "github"
|
||||
APPLEID: ${{ secrets.APPLEID }}
|
||||
APPLEIDPASS: ${{ secrets.APPLEIDPASS }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
||||
CSC_LINK: ${{ secrets.CSC_LINK }}
|
||||
GH_TOKEN: ${{ secrets.GH_PAT }}
|
||||
EP_PRE_RELEASE: true
|
||||
run: ./cmd electron build-mac
|
||||
|
||||
build-win:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
id: [ "com.dootask.task", "com.hitosea.task" ]
|
||||
runs-on: windows-latest
|
||||
environment: build
|
||||
|
||||
if: ${{ (startsWith(github.event.ref, 'refs/tags/v')) && (github.repository == 'kuaifan/dootask') }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- name: Build for Windows
|
||||
shell: powershell
|
||||
env:
|
||||
APPID: ${{ matrix.id }}
|
||||
PROVIDER: "github"
|
||||
GH_TOKEN: ${{ secrets.GH_PAT }}
|
||||
EP_PRE_RELEASE: true
|
||||
run: |
|
||||
npm install
|
||||
cd electron
|
||||
npm install
|
||||
cd ../
|
||||
mkdir -p ./electron/public
|
||||
cp ./electron/index.html ./electron/public/index.html
|
||||
npx mix --production -- --env --electron
|
||||
node ./electron/build.js build-win
|
||||
|
||||
34
.github/workflows/electron.yml
vendored
Normal file
34
.github/workflows/electron.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ build ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
environment: build
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-11]
|
||||
platform: [
|
||||
build-mac,
|
||||
build-mac-arm,
|
||||
build-win
|
||||
]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Use Node.js 14.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 14.x
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_PAT }}
|
||||
run: ./cmd electron ${{ matrix.platform }}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,7 +8,6 @@
|
||||
/vendor
|
||||
/build
|
||||
/tmp
|
||||
/CHANGELOG.md
|
||||
._*
|
||||
.env
|
||||
.idea
|
||||
@@ -20,6 +19,7 @@ Homestead.yaml
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
test.*
|
||||
composer.lock
|
||||
package-lock.json
|
||||
laravels-timer-process.pid
|
||||
.DS_Store
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "resources/drawio"]
|
||||
path = resources/drawio
|
||||
url = https://github.com/jgraph/drawio.git
|
||||
75
README.md
75
README.md
@@ -5,15 +5,10 @@ English | **[中文文档](./README_CN.md)**
|
||||
- [Screenshot Preview](README_PREVIEW.md)
|
||||
- [Demo site](http://www.dootask.com/)
|
||||
|
||||
**QQ Group**
|
||||
|
||||
Group No.: `546574618`
|
||||
|
||||
## Setup
|
||||
|
||||
- `Docker` & `Docker Compose v2.0+` must be installed
|
||||
- System: `Centos/Debian/Ubuntu/macOS`
|
||||
- Hardware suggestion: 2 cores and above 4G memory
|
||||
> `Docker` & `Docker Compose` must be installed
|
||||
|
||||
|
||||
### Deployment project
|
||||
|
||||
@@ -21,14 +16,14 @@ Group No.: `546574618`
|
||||
# 1、Clone the repository
|
||||
|
||||
# Clone projects on github
|
||||
git clone --depth=1 https://github.com/kuaifan/dootask.git
|
||||
# Or you can use gitee
|
||||
git clone --depth=1 https://gitee.com/aipaw/dootask.git
|
||||
git clone https://github.com/kuaifan/dootask.git
|
||||
# or you can use gitee
|
||||
git clone https://gitee.com/aipaw/dootask.git
|
||||
|
||||
# 2、Enter directory
|
||||
# 2、enter directory
|
||||
cd dootask
|
||||
|
||||
# 3、Installation(Custom port installation: ./cmd install --port 2222)
|
||||
# 3、Build project
|
||||
./cmd install
|
||||
```
|
||||
|
||||
@@ -42,7 +37,8 @@ cd dootask
|
||||
### Change port
|
||||
|
||||
```bash
|
||||
./cmd port 2222
|
||||
./cmd php bin/run --port=2222
|
||||
./cmd up -d
|
||||
```
|
||||
|
||||
### Stop server
|
||||
@@ -54,28 +50,18 @@ cd dootask
|
||||
./cmd start
|
||||
```
|
||||
|
||||
### Development compilation
|
||||
|
||||
```bash
|
||||
# Development mode, Mac OS only
|
||||
./cmd dev
|
||||
|
||||
# Production projects, macOS only
|
||||
./cmd prod
|
||||
```
|
||||
|
||||
### Shortcuts for running command
|
||||
|
||||
```bash
|
||||
# You can do this using the following command
|
||||
./cmd artisan "your command" # To run a artisan command
|
||||
./cmd php "your command" # To run a php command
|
||||
./cmd nginx "your command" # To run a nginx command
|
||||
./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)
|
||||
./cmd artisan "your command" // To run a artisan command
|
||||
./cmd php "your command" // To run a php command
|
||||
./cmd nginx "your command" // To run a nginx command
|
||||
./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
|
||||
@@ -86,7 +72,7 @@ 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
|
||||
# 2、Enter directory and run command
|
||||
./cmd https
|
||||
```
|
||||
|
||||
@@ -95,7 +81,7 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
**Note: Please back up your data before upgrading!**
|
||||
|
||||
```bash
|
||||
# Method 1: Running commands in a project
|
||||
# Method 1: enter directory and run command
|
||||
./cmd update
|
||||
|
||||
# Or method 2: use this method if method 1 fails
|
||||
@@ -106,30 +92,9 @@ git pull
|
||||
./cmd mysql recovery
|
||||
```
|
||||
|
||||
If 502 after the upgrade please run `./cmd restart` restart the service.
|
||||
|
||||
## Transfer
|
||||
|
||||
Follow these steps to complete the project migration after the new project is installed:
|
||||
|
||||
1. Backup original database
|
||||
|
||||
```bash
|
||||
# Run command under old project
|
||||
./cmd mysql backup
|
||||
```
|
||||
|
||||
2. Copy `database backup file` and `public/uploads` directory to the new project.
|
||||
|
||||
3. Restore database to new project
|
||||
```bash
|
||||
# Run command under new project
|
||||
./cmd mysql recovery
|
||||
```
|
||||
|
||||
## Uninstall
|
||||
|
||||
```bash
|
||||
# Running commands in a project
|
||||
# Enter directory and run command
|
||||
./cmd uninstall
|
||||
```
|
||||
|
||||
72
README_CN.md
72
README_CN.md
@@ -5,15 +5,10 @@
|
||||
- [截图预览](README_PREVIEW.md)
|
||||
- [演示站点](http://www.dootask.com/)
|
||||
|
||||
**QQ交流群**
|
||||
|
||||
- QQ群号: `546574618`
|
||||
|
||||
## 安装程序
|
||||
|
||||
- 必须安装:`Docker` 和 `Docker Compose v2.0+`
|
||||
- 支持环境:`Centos/Debian/Ubuntu/macOS`
|
||||
- 硬件建议:2核4G以上
|
||||
> 必须安装 `Docker` 和 `Docker Compose`
|
||||
|
||||
|
||||
### 部署项目
|
||||
|
||||
@@ -21,14 +16,14 @@
|
||||
# 1、克隆项目到您的本地或服务器
|
||||
|
||||
# 通过github克隆项目
|
||||
git clone --depth=1 https://github.com/kuaifan/dootask.git
|
||||
git clone https://github.com/kuaifan/dootask.git
|
||||
# 或者你也可以使用gitee
|
||||
git clone --depth=1 https://gitee.com/aipaw/dootask.git
|
||||
git clone https://gitee.com/aipaw/dootask.git
|
||||
|
||||
# 2、进入目录
|
||||
cd dootask
|
||||
|
||||
# 3、一键安装项目(自定义端口安装 ./cmd install --port 2222)
|
||||
# 3、一键构建项目
|
||||
./cmd install
|
||||
```
|
||||
|
||||
@@ -42,7 +37,8 @@ cd dootask
|
||||
### 更换端口
|
||||
|
||||
```bash
|
||||
./cmd port 2222
|
||||
./cmd php bin/run --port=2222
|
||||
./cmd up -d
|
||||
```
|
||||
|
||||
### 停止服务
|
||||
@@ -54,29 +50,18 @@ cd dootask
|
||||
./cmd start
|
||||
```
|
||||
|
||||
### 开发编译
|
||||
|
||||
```bash
|
||||
# 开发模式,仅限macOS
|
||||
./cmd dev
|
||||
|
||||
# 编译项目,仅限macOS
|
||||
./cmd prod
|
||||
```
|
||||
|
||||
|
||||
### 运行命令的快捷方式
|
||||
|
||||
```bash
|
||||
# 你可以使用以下命令来执行
|
||||
./cmd artisan "your command" # 运行 artisan 命令
|
||||
./cmd php "your command" # 运行 php 命令
|
||||
./cmd nginx "your command" # 运行 nginx 命令
|
||||
./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: 还原数据库)
|
||||
./cmd artisan "your command" // 运行 artisan 命令
|
||||
./cmd php "your command" // 运行 php 命令
|
||||
./cmd nginx "your command" // 运行 nginx 命令
|
||||
./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
|
||||
@@ -87,7 +72,7 @@ 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、在项目下运行命令
|
||||
# 2、进入项目所在目录,运行以下命令
|
||||
./cmd https
|
||||
```
|
||||
|
||||
@@ -96,7 +81,7 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
**注意:在升级之前请备份好你的数据!**
|
||||
|
||||
```bash
|
||||
# 方法1:在项目下运行命令
|
||||
# 方法1:进入项目所在目录,运行以下命令
|
||||
./cmd update
|
||||
|
||||
# (或者)方法2:如果方法1失败请使用此方法
|
||||
@@ -107,30 +92,9 @@ git pull
|
||||
./cmd mysql recovery
|
||||
```
|
||||
|
||||
如果升级后出现502请运行 `./cmd restart` 重启服务即可。
|
||||
|
||||
## 迁移项目
|
||||
|
||||
在新项目安装好之后按照以下步骤完成项目迁移:
|
||||
|
||||
1、备份原数据库
|
||||
|
||||
```bash
|
||||
# 在旧的项目下运行命令
|
||||
./cmd mysql backup
|
||||
```
|
||||
|
||||
2、将`数据库备份文件`及`public/uploads`目录拷贝至新项目
|
||||
|
||||
3、还原数据库至新项目
|
||||
```bash
|
||||
# 在新的项目下运行命令
|
||||
./cmd mysql recovery
|
||||
```
|
||||
|
||||
## 卸载项目
|
||||
|
||||
```bash
|
||||
# 在项目下运行命令
|
||||
# 进入项目所在目录,运行以下命令
|
||||
./cmd uninstall
|
||||
```
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
# 发布说明
|
||||
|
||||
## 通过 GitHub Actions 发布
|
||||
|
||||
1. 执行 `./cmd prod` 编译
|
||||
2. 执行 `node ./version.js` 制作版本
|
||||
3. 执行 `git commit` 相关操作
|
||||
4. 制作标签
|
||||
5. 推送标签
|
||||
|
||||
## 本地发布
|
||||
|
||||
1. 执行 `./cmd prod` 编译
|
||||
2. 执行 `node ./version.js` 制作版本
|
||||
3. 执行 `git commit` 相关操作
|
||||
4. 制作标签
|
||||
5. 执行 `./cmd electron` 相关操作
|
||||
1406
_ide_helper.php
1406
_ide_helper.php
File diff suppressed because it is too large
Load Diff
@@ -10,15 +10,8 @@ if (!function_exists('asset_main')) {
|
||||
if (!function_exists('seeders_at')) {
|
||||
function seeders_at($data)
|
||||
{
|
||||
$diff = time() - strtotime("2021-07-02");
|
||||
$diff = time() - strtotime("2021-07-01");
|
||||
$time = strtotime($data) + $diff;
|
||||
return date("Y-m-d H:i:s", $time);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('md5s')) {
|
||||
function md5s($val, $len = 16)
|
||||
{
|
||||
return substr(md5($val), 32 - $len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\File;
|
||||
use App\Models\ProjectTask;
|
||||
use App\Models\ProjectTaskFile;
|
||||
use App\Models\User;
|
||||
@@ -11,10 +10,7 @@ use App\Models\WebSocketDialogMsg;
|
||||
use App\Models\WebSocketDialogMsgRead;
|
||||
use App\Models\WebSocketDialogUser;
|
||||
use App\Module\Base;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Request;
|
||||
use Response;
|
||||
|
||||
/**
|
||||
* @apiDefine dialog
|
||||
@@ -24,50 +20,31 @@ use Response;
|
||||
class DialogController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @api {get} api/dialog/lists 01. 对话列表
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName lists
|
||||
* 对话列表
|
||||
*
|
||||
* @apiParam {Number} [page] 当前页,默认:1
|
||||
* @apiParam {Number} [pagesize] 每页显示数量,默认:100,最大:200
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function lists()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$list = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread'])
|
||||
$list = WebSocketDialog::select(['web_socket_dialogs.*'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->where('u.userid', $user->userid)
|
||||
->orderByDesc('u.top_at')
|
||||
->orderByDesc('web_socket_dialogs.last_at')
|
||||
->paginate(Base::getPaginate(200, 100));
|
||||
$list->transform(function (WebSocketDialog $item) use ($user) {
|
||||
return $item->formatData($user->userid);
|
||||
return WebSocketDialog::formatData($item, $user->userid);
|
||||
});
|
||||
//
|
||||
return Base::retSuccess('success', $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/one 02. 获取单个会话信息
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName one
|
||||
* 获取单个会话信息
|
||||
*
|
||||
* @apiParam {Number} dialog_id 对话ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function one()
|
||||
{
|
||||
@@ -75,31 +52,22 @@ class DialogController extends AbstractController
|
||||
//
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
//
|
||||
$item = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.mark_unread'])
|
||||
$item = WebSocketDialog::select(['web_socket_dialogs.*'])
|
||||
->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
|
||||
->where('web_socket_dialogs.id', $dialog_id)
|
||||
->where('u.userid', $user->userid)
|
||||
->first();
|
||||
if ($item) {
|
||||
$item = $item->formatData($user->userid);
|
||||
$item = WebSocketDialog::formatData($item, $user->userid);
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('success', $item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/msg/user 03. 打开会话
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName open__user
|
||||
* 打开会话
|
||||
*
|
||||
* @apiParam {Number} userid 对话会员ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function open__user()
|
||||
{
|
||||
@@ -114,7 +82,7 @@ class DialogController extends AbstractController
|
||||
if (empty($dialog)) {
|
||||
return Base::retError('打开会话失败');
|
||||
}
|
||||
$data = WebSocketDialog::find($dialog->id)?->formatData($user->userid);
|
||||
$data = WebSocketDialog::formatData(WebSocketDialog::find($dialog->id), $user->userid);
|
||||
if (empty($data)) {
|
||||
return Base::retError('打开会话错误');
|
||||
}
|
||||
@@ -122,21 +90,12 @@ class DialogController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/msg/lists 04. 获取消息列表
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__lists
|
||||
* 获取消息列表
|
||||
*
|
||||
* @apiParam {Number} dialog_id 对话ID
|
||||
*
|
||||
* @apiParam {Number} [page] 当前页,默认:1
|
||||
* @apiParam {Number} [pagesize] 每页显示数量,默认:50,最大:100
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function msg__lists()
|
||||
{
|
||||
@@ -146,80 +105,43 @@ class DialogController extends AbstractController
|
||||
//
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id);
|
||||
//
|
||||
$list = WebSocketDialogMsg::select([
|
||||
'web_socket_dialog_msgs.*',
|
||||
'read.mention',
|
||||
'read.read_at',
|
||||
])->leftJoin('web_socket_dialog_msg_reads as read', function ($leftJoin) use ($user) {
|
||||
$leftJoin
|
||||
->on('read.userid', '=', DB::raw($user->userid))
|
||||
->on('read.msg_id', '=', 'web_socket_dialog_msgs.id');
|
||||
})->where('web_socket_dialog_msgs.dialog_id', $dialog_id)->orderByDesc('web_socket_dialog_msgs.id')->paginate(Base::getPaginate(100, 50));
|
||||
$list = WebSocketDialogMsg::whereDialogId($dialog_id)->orderByDesc('id')->paginate(Base::getPaginate(100, 50));
|
||||
$list->transform(function (WebSocketDialogMsg $item) use ($user) {
|
||||
$item->is_read = $item->userid === $user->userid || WebSocketDialogMsgRead::whereMsgId($item->id)->whereUserid($user->userid)->value('read_at');
|
||||
return $item;
|
||||
});
|
||||
//
|
||||
if ($dialog->type == 'group' && $dialog->group_type == 'task') {
|
||||
$user->task_dialog_id = $dialog->id;
|
||||
$user->save();
|
||||
}
|
||||
//去掉标记未读
|
||||
$isMarkDialogUser = WebSocketDialogUser::whereDialogId($dialog->id)->whereUserid($user->userid)->whereMarkUnread(1)->first();
|
||||
if ($isMarkDialogUser) {
|
||||
$isMarkDialogUser->mark_unread = 0;
|
||||
$isMarkDialogUser->save();
|
||||
}
|
||||
//
|
||||
$data = $list->toArray();
|
||||
if ($list->currentPage() === 1) {
|
||||
$data['dialog'] = $dialog->formatData($user->userid);
|
||||
$data['dialog'] = WebSocketDialog::formatData($dialog, $user->userid);
|
||||
}
|
||||
return Base::retSuccess('success', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/msg/unread 05. 获取未读消息数量
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__unread
|
||||
*
|
||||
* @apiParam {Number} [dialog_id] 对话ID,留空获取总未读消息数量
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
* 未读消息
|
||||
*/
|
||||
public function msg__unread()
|
||||
{
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
//
|
||||
$builder = WebSocketDialogMsgRead::whereUserid(User::userid())->whereReadAt(null);
|
||||
if ($dialog_id > 0) {
|
||||
$builder->whereDialogId($dialog_id);
|
||||
}
|
||||
$unread = $builder->count();
|
||||
$unread = WebSocketDialogMsgRead::whereUserid(User::userid())->whereReadAt(null)->count();
|
||||
return Base::retSuccess('success', [
|
||||
'unread' => $unread,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} api/dialog/msg/sendtext 06. 发送消息
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__sendtext
|
||||
* 发送消息
|
||||
*
|
||||
* @apiParam {Number} dialog_id 对话ID
|
||||
* @apiParam {String} text 消息内容
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function msg__sendtext()
|
||||
{
|
||||
Base::checkClientVersion('0.13.33');
|
||||
$user = User::auth();
|
||||
//
|
||||
$chat_nickname = Base::settingFind('system', 'chat_nickname');
|
||||
@@ -230,62 +152,41 @@ class DialogController extends AbstractController
|
||||
}
|
||||
}
|
||||
//
|
||||
$dialog_id = Base::getPostInt('dialog_id');
|
||||
$text = trim(Base::getPostValue('text'));
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$text = trim(Request::input('text'));
|
||||
//
|
||||
WebSocketDialog::checkDialog($dialog_id);
|
||||
//
|
||||
$text = WebSocketDialogMsg::formatMsg($text, $dialog_id);
|
||||
if (mb_strlen($text) < 1) {
|
||||
return Base::retError('消息内容不能为空');
|
||||
} elseif (mb_strlen($text) > 20000) {
|
||||
return Base::retError('消息内容最大不能超过20000字');
|
||||
}
|
||||
if (mb_strlen($text) > 2000) {
|
||||
$array = mb_str_split($text, 2000);
|
||||
} else {
|
||||
$array = [$text];
|
||||
}
|
||||
//
|
||||
$list = [];
|
||||
foreach ($array as $item) {
|
||||
$res = WebSocketDialogMsg::sendMsg($dialog_id, 'text', ['text' => $item], $user->userid);
|
||||
if (Base::isSuccess($res)) {
|
||||
$list[] = $res['data'];
|
||||
}
|
||||
}
|
||||
WebSocketDialog::checkDialog($dialog_id);
|
||||
//
|
||||
return Base::retSuccess('发送成功', $list);
|
||||
$msg = [
|
||||
'text' => $text
|
||||
];
|
||||
//
|
||||
return WebSocketDialogMsg::sendMsg($dialog_id, 'text', $msg, $user->userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} api/dialog/msg/sendfile 07. 文件上传
|
||||
* {post}文件上传
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__sendfile
|
||||
*
|
||||
* @apiParam {Number} dialog_id 对话ID
|
||||
* @apiParam {Number} [image_attachment] 图片是否也存到附件
|
||||
* @apiParam {String} [filename] post-文件名称
|
||||
* @apiParam {String} [image64] post-base64图片(二选一)
|
||||
* @apiParam {File} [files] post-文件对象(二选一)
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
* @apiParam {Number} dialog_id 对话ID
|
||||
* @apiParam {String} [filename] post-文件名称
|
||||
* @apiParam {String} [image64] post-base64图片(二选一)
|
||||
* @apiParam {File} [files] post-文件对象(二选一)
|
||||
*/
|
||||
public function msg__sendfile()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$dialog_id = Base::getPostInt('dialog_id');
|
||||
$image_attachment = Base::getPostInt('image_attachment');
|
||||
//
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id);
|
||||
//
|
||||
$path = "uploads/chat/" . date("Ym") . "/" . $dialog_id . "/";
|
||||
$path = "uploads/chat/" . $user->userid . "/";
|
||||
$image64 = Base::getPostValue('image64');
|
||||
$fileName = Base::getPostValue('filename');
|
||||
if ($image64) {
|
||||
@@ -297,7 +198,7 @@ class DialogController extends AbstractController
|
||||
} else {
|
||||
$data = Base::upload([
|
||||
"file" => Request::file('files'),
|
||||
"type" => 'more',
|
||||
"type" => 'file',
|
||||
"path" => $path,
|
||||
"fileName" => $fileName,
|
||||
]);
|
||||
@@ -310,8 +211,8 @@ class DialogController extends AbstractController
|
||||
$fileData['thumb'] = Base::unFillUrl($fileData['thumb']);
|
||||
$fileData['size'] *= 1024;
|
||||
//
|
||||
if ($dialog->type === 'group' && $dialog->group_type === 'task') { // 任务群组保存文件
|
||||
if ($image_attachment || !in_array($fileData['ext'], File::imageExt)) { // 如果是图片不保存
|
||||
if ($dialog->type === 'group') {
|
||||
if ($dialog->group_type === 'task') {
|
||||
$task = ProjectTask::whereDialogId($dialog->id)->first();
|
||||
if ($task) {
|
||||
$file = ProjectTaskFile::createInstance([
|
||||
@@ -340,18 +241,9 @@ class DialogController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/msg/readlist 08. 获取消息阅读情况
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__readlist
|
||||
* 获取消息阅读情况
|
||||
*
|
||||
* @apiParam {Number} msg_id 消息ID(需要是消息的发送人)
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function msg__readlist()
|
||||
{
|
||||
@@ -367,424 +259,4 @@ class DialogController extends AbstractController
|
||||
$read = WebSocketDialogMsgRead::whereMsgId($msg_id)->get();
|
||||
return Base::retSuccess('success', $read ?: []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/msg/detail 09. 消息详情
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__detail
|
||||
*
|
||||
* @apiParam {Number} msg_id 消息ID
|
||||
* @apiParam {String} only_update_at 仅获取update_at字段
|
||||
* - no (默认)
|
||||
* - yes
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function msg__detail()
|
||||
{
|
||||
User::auth();
|
||||
//
|
||||
$msg_id = intval(Request::input('msg_id'));
|
||||
$only_update_at = Request::input('only_update_at', 'no');
|
||||
//
|
||||
$dialogMsg = WebSocketDialogMsg::whereId($msg_id)->first();
|
||||
if (empty($dialogMsg)) {
|
||||
return Base::retError("文件不存在");
|
||||
}
|
||||
//
|
||||
if ($only_update_at == 'yes') {
|
||||
return Base::retSuccess('success', [
|
||||
'id' => $dialogMsg->id,
|
||||
'update_at' => Carbon::parse($dialogMsg->updated_at)->toDateTimeString()
|
||||
]);
|
||||
}
|
||||
//
|
||||
$data = $dialogMsg->toArray();
|
||||
//
|
||||
if ($data['type'] == 'file') {
|
||||
$msg = Base::json2array($dialogMsg->getRawOriginal('msg'));
|
||||
$msg = File::formatFileData($msg);
|
||||
$data['content'] = $msg['content'];
|
||||
$data['file_mode'] = $msg['file_mode'];
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('success', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/msg/download 10. 文件下载
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__download
|
||||
*
|
||||
* @apiParam {Number} msg_id 消息ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function msg__download()
|
||||
{
|
||||
User::auth();
|
||||
//
|
||||
$msg_id = intval(Request::input('msg_id'));
|
||||
//
|
||||
$msg = WebSocketDialogMsg::whereId($msg_id)->first();
|
||||
if (empty($msg)) {
|
||||
abort(403, "This file not exist.");
|
||||
}
|
||||
if ($msg->type != 'file') {
|
||||
abort(403, "This file not support download.");
|
||||
}
|
||||
$array = Base::json2array($msg->getRawOriginal('msg'));
|
||||
//
|
||||
return Response::download(public_path($array['path']), $array['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/msg/withdraw 11. 聊天消息撤回
|
||||
*
|
||||
* @apiDescription 消息撤回限制24小时内,需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__withdraw
|
||||
*
|
||||
* @apiParam {Number} msg_id 消息ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function msg__withdraw()
|
||||
{
|
||||
$user = User::auth();
|
||||
$msg_id = intval(Request::input("msg_id"));
|
||||
$msg = WebSocketDialogMsg::whereId($msg_id)->whereUserid($user->userid)->first();
|
||||
if (empty($msg)) {
|
||||
return Base::retError("消息不存在或已被删除");
|
||||
}
|
||||
$msg->deleteMsg();
|
||||
return Base::retSuccess("success");
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/top 12. 会话置顶
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName top
|
||||
*
|
||||
* @apiParam {Number} dialog_id 会话ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function top()
|
||||
{
|
||||
$user = User::auth();
|
||||
$dialogId = intval(Request::input('dialog_id'));
|
||||
$dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
|
||||
if (!$dialogUser) {
|
||||
return Base::retError("会话不存在");
|
||||
}
|
||||
$dialogUser->top_at = $dialogUser->top_at ? null : Carbon::now();
|
||||
$dialogUser->save();
|
||||
return Base::retSuccess("success", [
|
||||
'id' => $dialogUser->dialog_id,
|
||||
'top_at' => $dialogUser->top_at?->toDateTimeString(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/msg/mark 13. 消息标记操作
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName msg__mark
|
||||
*
|
||||
* @apiParam {Number} dialog_id 会话ID
|
||||
* @apiParam {String} type 类型
|
||||
* - read
|
||||
* - unread
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function msg__mark()
|
||||
{
|
||||
$user = User::auth();
|
||||
$dialogId = intval(Request::input('dialog_id'));
|
||||
$type = Request::input('type');
|
||||
$dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
|
||||
if (!$dialogUser) {
|
||||
return Base::retError("会话不存在");
|
||||
}
|
||||
switch ($type) {
|
||||
case 'read':
|
||||
WebSocketDialogMsgRead::whereUserid($user->userid)
|
||||
->whereReadAt(null)
|
||||
->whereDialogId($dialogId)
|
||||
->chunkById(100, function ($list) {
|
||||
WebSocketDialogMsgRead::onlyMarkRead($list);
|
||||
});
|
||||
$dialogUser->mark_unread = 0;
|
||||
$dialogUser->save();
|
||||
break;
|
||||
|
||||
case 'unread':
|
||||
$dialogUser->mark_unread = 1;
|
||||
$dialogUser->save();
|
||||
break;
|
||||
|
||||
default:
|
||||
return Base::retError("参数错误");
|
||||
}
|
||||
return Base::retSuccess("success", [
|
||||
'id' => $dialogId,
|
||||
'mark_unread' => $dialogUser->mark_unread,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/group/add 14. 新增群组
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName group__add
|
||||
*
|
||||
* @apiParam {Array} userids 群成员,格式: [userid1, userid2, userid3]
|
||||
* @apiParam {String} chat_name 群名称
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function group__add()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$userids = Request::input('userids');
|
||||
$chatName = trim(Request::input('chat_name'));
|
||||
//
|
||||
if (!is_array($userids)) {
|
||||
return Base::retError('请选择群成员');
|
||||
}
|
||||
$userids = array_merge([$user->userid], $userids);
|
||||
$userids = array_values(array_filter(array_unique($userids)));
|
||||
if (count($userids) < 2) {
|
||||
return Base::retError('群成员至少2人');
|
||||
}
|
||||
//
|
||||
if (empty($chatName)) {
|
||||
$array = [];
|
||||
foreach ($userids as $userid) {
|
||||
$array[] = User::userid2nickname($userid);
|
||||
if (count($array) >= 8 || strlen(implode(", ", $array)) > 100) {
|
||||
$array[] = "...";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$chatName = implode(", ", $array);
|
||||
}
|
||||
$dialog = WebSocketDialog::createGroup($chatName, $userids, 'user', $user->userid);
|
||||
if (empty($dialog)) {
|
||||
return Base::retError('创建群组失败');
|
||||
}
|
||||
$data = WebSocketDialog::find($dialog->id)?->formatData($user->userid);
|
||||
$dialog->pushMsg("groupAdd", $data, $userids);
|
||||
return Base::retSuccess('创建成功', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/group/edit 15. 修改群组
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName group__edit
|
||||
*
|
||||
* @apiParam {Number} dialog_id 会话ID
|
||||
* @apiParam {String} chat_name 群名称
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function group__edit()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$chatName = trim(Request::input('chat_name'));
|
||||
//
|
||||
if (mb_strlen($chatName) < 2) {
|
||||
return Base::retError('群名称至少2个字');
|
||||
}
|
||||
if (mb_strlen($chatName) > 100) {
|
||||
return Base::retError('群名称最长限制100个字');
|
||||
}
|
||||
//
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id, true);
|
||||
//
|
||||
$dialog->name = $chatName;
|
||||
$dialog->save();
|
||||
return Base::retSuccess('修改成功', [
|
||||
'id' => $dialog->id,
|
||||
'name' => $dialog->name,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/group/user 16. 获取群成员
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName group__user
|
||||
*
|
||||
* @apiParam {Number} dialog_id 会话ID
|
||||
* @apiParam {Number} [getuser] 获取会员详情(1: 返回会员昵称、邮箱等基本信息,0: 默认不返回)
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function group__user()
|
||||
{
|
||||
User::auth();
|
||||
//
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$getuser = intval(Request::input('getuser', 0));
|
||||
//
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id);
|
||||
//
|
||||
$data = $dialog->dialogUser->toArray();
|
||||
if ($getuser === 1) {
|
||||
$array = [];
|
||||
foreach ($data as $item) {
|
||||
$res = User::userid2basic($item['userid']);
|
||||
if ($res) {
|
||||
$array[] = array_merge($item, $res->toArray());
|
||||
}
|
||||
}
|
||||
$data = $array;
|
||||
}
|
||||
return Base::retSuccess('success', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/group/adduser 17. 添加群成员
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName group__adduser
|
||||
*
|
||||
* @apiParam {Number} dialog_id 会话ID
|
||||
* @apiParam {Array} userids 新增的群成员,格式: [userid1, userid2, userid3]
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function group__adduser()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$userids = Request::input('userids');
|
||||
//
|
||||
if (!is_array($userids)) {
|
||||
return Base::retError('请选择群成员');
|
||||
}
|
||||
//
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id, true);
|
||||
//
|
||||
$dialog->checkGroup();
|
||||
$dialog->joinGroup($userids);
|
||||
$dialog->pushMsg("groupJoin", $dialog->formatData($user->userid), $userids);
|
||||
return Base::retSuccess('添加成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/group/deluser 18. 移出(退出)群成员
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName group__adduser
|
||||
*
|
||||
* @apiParam {Number} dialog_id 会话ID
|
||||
* @apiParam {Array} userids 移出的群成员,格式: [userid1, userid2, userid3]
|
||||
* - 留空表示自己退出
|
||||
* - 有值表示移出,仅限群主操作
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function group__deluser()
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$userids = Request::input('userids');
|
||||
//
|
||||
$type = 'remove';
|
||||
if (empty($userids)) {
|
||||
$type = 'exit';
|
||||
$userids = [$user->userid];
|
||||
}
|
||||
//
|
||||
if (!is_array($userids)) {
|
||||
return Base::retError('请选择群成员');
|
||||
}
|
||||
//
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id, $type === 'remove');
|
||||
//
|
||||
$dialog->checkGroup();
|
||||
$dialog->exitGroup($userids);
|
||||
$dialog->pushMsg("groupExit", null, $userids);
|
||||
return Base::retSuccess($type === 'remove' ? '移出成功' : '退出成功');
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/dialog/group/disband 19. 解散群组
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup dialog
|
||||
* @apiName group__disband
|
||||
*
|
||||
* @apiParam {Number} dialog_id 会话ID
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function group__disband()
|
||||
{
|
||||
User::auth();
|
||||
//
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
//
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id, true);
|
||||
//
|
||||
$dialog->checkGroup();
|
||||
$dialog->deleteDialog();
|
||||
$dialog->pushMsg("groupDelete");
|
||||
return Base::retSuccess('解散成功');
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,474 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Models\AbstractModel;
|
||||
use App\Models\ProjectTask;
|
||||
use App\Models\Report;
|
||||
use App\Models\ReportReceive;
|
||||
use App\Models\User;
|
||||
use App\Module\Base;
|
||||
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;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
/**
|
||||
* @apiDefine report
|
||||
*
|
||||
* 汇报
|
||||
*/
|
||||
class ReportController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @api {get} api/report/my 01. 我发送的汇报
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup report
|
||||
* @apiName my
|
||||
*
|
||||
* @apiParam {Object} [keys] 搜索条件
|
||||
* - keys.type: 汇报类型,weekly:周报,daily:日报
|
||||
* - keys.created_at: 汇报时间
|
||||
* @apiParam {Number} [page] 当前页,默认:1
|
||||
* @apiParam {Number} [pagesize] 每页显示数量,默认:20,最大:50
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function my(): array
|
||||
{
|
||||
$user = User::auth();
|
||||
//
|
||||
$builder = Report::with(['receivesUser'])->whereUserid($user->userid);
|
||||
$keys = Request::input('keys');
|
||||
if (is_array($keys)) {
|
||||
if (in_array($keys['type'], [Report::WEEKLY, Report::DAILY])) {
|
||||
$builder->whereType($keys['type']);
|
||||
}
|
||||
if (is_array($keys['created_at'])) {
|
||||
if ($keys['created_at'][0] > 0) $builder->where('created_at', '>=', date('Y-m-d H:i:s', Base::dayTimeF($keys['created_at'][0])));
|
||||
if ($keys['created_at'][1] > 0) $builder->where('created_at', '<=', date('Y-m-d H:i:s', Base::dayTimeE($keys['created_at'][1])));
|
||||
}
|
||||
}
|
||||
$list = $builder->orderByDesc('created_at')->paginate(Base::getPaginate(50, 20));
|
||||
return Base::retSuccess('success', $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/report/receive 02. 我接收的汇报
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup report
|
||||
* @apiName receive
|
||||
*
|
||||
* @apiParam {Object} [keys] 搜索条件
|
||||
* - keys.key: 关键词
|
||||
* - keys.type: 汇报类型,weekly:周报,daily:日报
|
||||
* - keys.created_at: 汇报时间
|
||||
* @apiParam {Number} [page] 当前页,默认:1
|
||||
* @apiParam {Number} [pagesize] 每页显示数量,默认:20,最大:50
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function receive(): array
|
||||
{
|
||||
$user = User::auth();
|
||||
$builder = Report::with(['receivesUser']);
|
||||
$builder->whereHas("receivesUser", function ($query) use ($user) {
|
||||
$query->where("report_receives.userid", $user->userid);
|
||||
});
|
||||
$keys = Request::input('keys');
|
||||
if (is_array($keys)) {
|
||||
if ($keys['key']) {
|
||||
$builder->where(function($query) use ($keys) {
|
||||
$query->whereHas('sendUser', function ($q2) use ($keys) {
|
||||
$q2->where("users.email", "LIKE", "%{$keys['key']}%");
|
||||
})->orWhere("title", "LIKE", "%{$keys['key']}%");
|
||||
});
|
||||
}
|
||||
if (in_array($keys['type'], [Report::WEEKLY, Report::DAILY])) {
|
||||
$builder->whereType($keys['type']);
|
||||
}
|
||||
if (is_array($keys['created_at'])) {
|
||||
if ($keys['created_at'][0] > 0) $builder->where('created_at', '>=', date('Y-m-d H:i:s', Base::dayTimeF($keys['created_at'][0])));
|
||||
if ($keys['created_at'][1] > 0) $builder->where('created_at', '<=', date('Y-m-d H:i:s', Base::dayTimeE($keys['created_at'][1])));
|
||||
}
|
||||
}
|
||||
$list = $builder->orderByDesc('created_at')->paginate(Base::getPaginate(50, 20));
|
||||
if ($list->items()) {
|
||||
foreach ($list->items() as $item) {
|
||||
$item->receive_time = ReportReceive::query()->whereRid($item["id"])->whereUserid($user->userid)->value("receive_time");
|
||||
}
|
||||
}
|
||||
return Base::retSuccess('success', $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/report/store 03. 保存并发送工作汇报
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup report
|
||||
* @apiName store
|
||||
*
|
||||
* @apiParam {Number} [id] 汇报ID
|
||||
* @apiParam {String} [title] 汇报标题
|
||||
* @apiParam {Array} [type] 汇报类型,weekly:周报,daily:日报
|
||||
* @apiParam {Number} [content] 内容
|
||||
* @apiParam {Number} [receive] 汇报对象
|
||||
* @apiParam {Number} [offset] 偏移量
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function store(): array
|
||||
{
|
||||
$input = [
|
||||
"id" => Base::getPostValue("id", 0),
|
||||
"title" => Base::getPostValue("title"),
|
||||
"type" => Base::getPostValue("type"),
|
||||
"content" => Base::getPostValue("content"),
|
||||
"receive" => Base::getPostValue("receive"),
|
||||
// 以当前日期为基础的周期偏移量。例如选择了上一周那么就是 -1,上一天同理。
|
||||
"offset" => Base::getPostValue("offset", 0),
|
||||
];
|
||||
$validator = Validator::make($input, [
|
||||
'id' => 'numeric',
|
||||
'title' => 'required',
|
||||
'type' => ['required', Rule::in([Report::WEEKLY, Report::DAILY])],
|
||||
'content' => 'required',
|
||||
'receive' => 'required',
|
||||
'offset' => ['numeric', 'max:0'],
|
||||
], [
|
||||
'id.numeric' => 'ID只能是数字',
|
||||
'title.required' => '请填写标题',
|
||||
'type.required' => '请选择汇报类型',
|
||||
'type.in' => '汇报类型错误',
|
||||
'content.required' => '请填写汇报内容',
|
||||
'receive.required' => '请选择接收人',
|
||||
'offset.numeric' => '工作汇报周期格式错误,只能是数字',
|
||||
'offset.max' => '只能提交当天/本周或者之前的的工作汇报',
|
||||
]);
|
||||
if ($validator->fails())
|
||||
return Base::retError($validator->errors()->first());
|
||||
|
||||
$user = User::auth();
|
||||
// 接收人
|
||||
if (is_array($input["receive"])) {
|
||||
// 删除当前登录人
|
||||
$input["receive"] = array_diff($input["receive"], [$user->userid]);
|
||||
|
||||
// 查询用户是否存在
|
||||
if (count($input["receive"]) !== User::whereIn("userid", $input["receive"])->count())
|
||||
return Base::retError("用户不存在");
|
||||
|
||||
foreach ($input["receive"] as $userid) {
|
||||
$input["receive_content"][] = [
|
||||
"receive_time" => Carbon::now()->toDateTimeString(),
|
||||
"userid" => $userid,
|
||||
"read" => 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// 在事务中运行
|
||||
return AbstractModel::transaction(function () use ($input, $user) {
|
||||
$id = $input["id"];
|
||||
if ($id) {
|
||||
// 编辑
|
||||
$report = Report::getOne($id);
|
||||
$report->updateInstance([
|
||||
"title" => $input["title"],
|
||||
"type" => $input["type"],
|
||||
"content" => htmlspecialchars($input["content"]),
|
||||
]);
|
||||
} else {
|
||||
// 生成唯一标识
|
||||
$sign = Report::generateSign($input["type"], $input["offset"]);
|
||||
// 检查唯一标识是否存在
|
||||
if (empty($input["id"])) {
|
||||
if (Report::query()->whereSign($sign)->whereType($input["type"])->count() > 0)
|
||||
throw new ApiException("请勿重复提交工作汇报");
|
||||
}
|
||||
$report = Report::createInstance([
|
||||
"title" => $input["title"],
|
||||
"type" => $input["type"],
|
||||
"content" => htmlspecialchars($input["content"]),
|
||||
"userid" => $user->userid,
|
||||
"sign" => $sign,
|
||||
]);
|
||||
}
|
||||
|
||||
$report->save();
|
||||
if (!empty($input["receive_content"])) {
|
||||
// 删除关联
|
||||
$report->Receives()->delete();
|
||||
// 保存接收人
|
||||
$report->Receives()->createMany($input["receive_content"]);
|
||||
}
|
||||
|
||||
// 推送消息
|
||||
$userids = [];
|
||||
foreach ($input["receive_content"] as $item) {
|
||||
$userids[] = $item['userid'];
|
||||
}
|
||||
if ($userids) {
|
||||
$params = [
|
||||
'ignoreFd' => Request::header('fd'),
|
||||
'userid' => $userids,
|
||||
'msg' => [
|
||||
'type' => 'report',
|
||||
'action' => 'unreadUpdate',
|
||||
]
|
||||
];
|
||||
Task::deliver(new PushTask($params, false));
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('保存成功', $report);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/report/template 04. 生成汇报模板
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup report
|
||||
* @apiName template
|
||||
*
|
||||
* @apiParam {Array} [type] 汇报类型,weekly:周报,daily:日报
|
||||
* @apiParam {Number} [offset] 偏移量
|
||||
* @apiParam {String} [date] 时间
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function template(): array
|
||||
{
|
||||
$user = User::auth();
|
||||
$type = trim(Request::input("type"));
|
||||
$offset = abs(intval(Request::input("offset", 0)));
|
||||
$id = intval(Request::input("offset", 0));
|
||||
$now_dt = trim(Request::input("date")) ? Carbon::parse(Request::input("date")) : Carbon::now();
|
||||
// 获取开始时间
|
||||
if ($type === Report::DAILY) {
|
||||
$start_time = Carbon::today();
|
||||
if ($offset > 0) {
|
||||
// 将当前时间调整为偏移量当天结束
|
||||
$now_dt->subDays($offset)->endOfDay();
|
||||
// 开始时间偏移量计算
|
||||
$start_time->subDays($offset);
|
||||
}
|
||||
$end_time = Carbon::instance($start_time)->endOfDay();
|
||||
} else {
|
||||
$start_time = Carbon::now();
|
||||
if ($offset > 0) {
|
||||
// 将当前时间调整为偏移量当周结束
|
||||
$now_dt->subWeeks($offset)->endOfDay();
|
||||
// 开始时间偏移量计算
|
||||
$start_time->subWeeks($offset);
|
||||
}
|
||||
$start_time->startOfWeek();
|
||||
$end_time = Carbon::instance($start_time)->endOfWeek();
|
||||
}
|
||||
// 生成唯一标识
|
||||
$sign = Report::generateSign($type, 0, Carbon::instance($start_time));
|
||||
$one = Report::whereSign($sign)->whereType($type)->first();
|
||||
// 如果已经提交了相关汇报
|
||||
if ($one && $id > 0) {
|
||||
return Base::retSuccess('success', [
|
||||
"content" => $one->content,
|
||||
"title" => $one->title,
|
||||
"id" => $one->id,
|
||||
]);
|
||||
}
|
||||
|
||||
// 已完成的任务
|
||||
$completeContent = "";
|
||||
$complete_task = ProjectTask::query()
|
||||
->whereNotNull("complete_at")
|
||||
->whereBetween("complete_at", [$start_time->toDateTimeString(), $end_time->toDateTimeString()])
|
||||
->whereHas("taskUser", function ($query) use ($user) {
|
||||
$query->where("userid", $user->userid);
|
||||
})
|
||||
->orderByDesc("id")
|
||||
->get();
|
||||
if ($complete_task->isNotEmpty()) {
|
||||
foreach ($complete_task as $task) {
|
||||
$complete_at = Carbon::parse($task->complete_at);
|
||||
$pre = $type == Report::WEEKLY ? ('<span>[' . Base::Lang('周' . ['日', '一', '二', '三', '四', '五', '六'][$complete_at->dayOfWeek]) . ']</span> ') : '';
|
||||
$completeContent .= '<li>' . $pre . $task->name . '</li>';
|
||||
}
|
||||
} else {
|
||||
$completeContent = '<li> </li>';
|
||||
}
|
||||
|
||||
// 未完成的任务
|
||||
$unfinishedContent = "";
|
||||
$unfinished_task = ProjectTask::query()
|
||||
->whereNull("complete_at")
|
||||
->whereNotNull("start_at")
|
||||
->where("end_at", "<", $end_time->toDateTimeString())
|
||||
->whereHas("taskUser", function ($query) use ($user) {
|
||||
$query->where("userid", $user->userid);
|
||||
})
|
||||
->orderByDesc("id")
|
||||
->get();
|
||||
if ($unfinished_task->isNotEmpty()) {
|
||||
foreach ($unfinished_task as $task) {
|
||||
empty($task->end_at) || $end_at = Carbon::parse($task->end_at);
|
||||
$pre = (!empty($end_at) && $end_at->lt($now_dt)) ? '<span style="color:#ff0000;">[' . Base::Lang('超期') . ']</span> ' : '';
|
||||
$unfinishedContent .= '<li>' . $pre . $task->name . '</li>';
|
||||
}
|
||||
} else {
|
||||
$unfinishedContent = '<li> </li>';
|
||||
}
|
||||
// 生成标题
|
||||
if ($type === Report::WEEKLY) {
|
||||
$title = $user->nickname . "的周报[" . $start_time->format("m/d") . "-" . $end_time->format("m/d") . "]";
|
||||
$title .= "[" . $start_time->month . "月第" . $start_time->weekOfMonth . "周]";
|
||||
} else {
|
||||
$title = $user->nickname . "的日报[" . $start_time->format("Y/m/d") . "]";
|
||||
}
|
||||
$data = [
|
||||
"time" => $start_time->toDateTimeString(),
|
||||
"complete_task" => $complete_task,
|
||||
"unfinished_task" => $unfinished_task,
|
||||
"content" => '<h2>' . Base::Lang('已完成工作') . '</h2><ol>' .
|
||||
$completeContent . '</ol><h2>' .
|
||||
Base::Lang('未完成的工作') . '</h2><ol>' .
|
||||
$unfinishedContent . '</ol>',
|
||||
"title" => $title,
|
||||
];
|
||||
if ($one) {
|
||||
$data['id'] = $one->id;
|
||||
}
|
||||
return Base::retSuccess('success', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/report/detail 05. 报告详情
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup report
|
||||
* @apiName detail
|
||||
*
|
||||
* @apiParam {Number} [id] 报告id
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function detail(): array
|
||||
{
|
||||
$user = User::auth();
|
||||
$id = intval(trim(Request::input("id")));
|
||||
if (empty($id))
|
||||
return Base::retError("缺少ID参数");
|
||||
|
||||
$one = Report::getOne($id);
|
||||
$one->type_val = $one->getRawOriginal("type");
|
||||
|
||||
// 标记为已读
|
||||
if (!empty($one->receivesUser)) {
|
||||
foreach ($one->receivesUser as $item) {
|
||||
if ($item->userid === $user->userid && $item->pivot->read === 0) {
|
||||
$one->receivesUser()->updateExistingPivot($user->userid, [
|
||||
"read" => 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Base::retSuccess("success", $one);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/report/last_submitter 06. 获取最后一次提交的接收人
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup report
|
||||
* @apiName last_submitter
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function last_submitter(): array
|
||||
{
|
||||
$one = Report::getLastOne();
|
||||
return Base::retSuccess("success", empty($one["receives"]) ? [] : $one["receives"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/report/unread 07. 获取未读
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup report
|
||||
* @apiName unread
|
||||
*
|
||||
* @apiParam {Number} [userid] 用户id
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function unread(): array
|
||||
{
|
||||
$userid = intval(trim(Request::input("userid")));
|
||||
$user = empty($userid) ? User::auth() : User::find($userid);
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/report/read 08. 标记汇报已读,可批量
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup report
|
||||
* @apiName read
|
||||
*
|
||||
* @apiParam {String} [ids] 报告id
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function read(): array
|
||||
{
|
||||
$user = User::auth();
|
||||
$ids = Request::input("ids");
|
||||
if (!is_array($ids) && !is_string($ids)) {
|
||||
return Base::retError("请传入正确的工作汇报Id");
|
||||
}
|
||||
|
||||
if (is_string($ids)) {
|
||||
$ids = explode(",", $ids);
|
||||
}
|
||||
|
||||
$data = Report::with(["receivesUser" => function (BelongsToMany $query) use ($user) {
|
||||
$query->where("report_receives.userid", $user->userid)->where("read", 0);
|
||||
}])->whereIn("id", $ids)->get();
|
||||
|
||||
if ($data->isNotEmpty()) {
|
||||
foreach ($data as $item) {
|
||||
(!empty($item->receivesUser) && $item->receivesUser->isNotEmpty()) && $item->receivesUser()->updateExistingPivot($user->userid, [
|
||||
"read" => 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
return Base::retSuccess("success", $data);
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Module\Base;
|
||||
use Guanguans\Notify\Factory;
|
||||
use Guanguans\Notify\Messages\EmailMessage;
|
||||
use Request;
|
||||
use Response;
|
||||
|
||||
@@ -26,8 +24,7 @@ class SystemController extends AbstractController
|
||||
*
|
||||
* @apiParam {String} type
|
||||
* - get: 获取(默认)
|
||||
* - all: 获取所有(需要管理员权限)
|
||||
* - save: 保存设置(参数:['reg', 'reg_invite', 'login_code', 'password_policy', 'project_invite', 'chat_nickname', 'auto_archived', 'archived_day', 'start_home', 'home_footer'])
|
||||
* - save: 保存设置(参数:reg、login_code、password_policy、chat_nickname)
|
||||
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@@ -43,110 +40,25 @@ class SystemController extends AbstractController
|
||||
User::auth('admin');
|
||||
$all = Request::input();
|
||||
foreach ($all AS $key => $value) {
|
||||
if (!in_array($key, [
|
||||
'reg',
|
||||
'reg_invite',
|
||||
'login_code',
|
||||
'password_policy',
|
||||
'project_invite',
|
||||
'chat_nickname',
|
||||
'auto_archived',
|
||||
'archived_day',
|
||||
'start_home',
|
||||
'home_footer'
|
||||
])) {
|
||||
if (!in_array($key, ['reg', 'login_code', 'password_policy', 'chat_nickname'])) {
|
||||
unset($all[$key]);
|
||||
}
|
||||
}
|
||||
$all['archived_day'] = floatval($all['archived_day']);
|
||||
if ($all['auto_archived'] == 'open') {
|
||||
if ($all['archived_day'] <= 0) {
|
||||
return Base::retError('自动归档时间不可小于1天!');
|
||||
} elseif ($all['archived_day'] > 100) {
|
||||
return Base::retError('自动归档时间不可大于100天!');
|
||||
}
|
||||
}
|
||||
$setting = Base::setting('system', Base::newTrim($all));
|
||||
} else {
|
||||
$setting = Base::setting('system');
|
||||
}
|
||||
//
|
||||
if ($type == 'all' || $type == 'save') {
|
||||
User::auth('admin');
|
||||
$setting['reg_invite'] = $setting['reg_invite'] ?: Base::generatePassword(8);
|
||||
} else {
|
||||
if (isset($setting['reg_invite'])) unset($setting['reg_invite']);
|
||||
}
|
||||
//
|
||||
$setting['reg'] = $setting['reg'] ?: 'open';
|
||||
$setting['login_code'] = $setting['login_code'] ?: 'auto';
|
||||
$setting['password_policy'] = $setting['password_policy'] ?: 'simple';
|
||||
$setting['project_invite'] = $setting['project_invite'] ?: 'open';
|
||||
$setting['chat_nickname'] = $setting['chat_nickname'] ?: 'optional';
|
||||
$setting['auto_archived'] = $setting['auto_archived'] ?: 'close';
|
||||
$setting['archived_day'] = floatval($setting['archived_day']) ?: 7;
|
||||
$setting['start_home'] = $setting['start_home'] ?: 'close';
|
||||
//
|
||||
return Base::retSuccess('success', $setting ?: json_decode('{}'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/setting/email 02. 获取邮箱设置、保存邮箱设置(限管理员)
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName setting__email
|
||||
*
|
||||
* @apiParam {String} type
|
||||
* - get: 获取(默认)
|
||||
* - save: 保存设置(参数:['smtp_server', 'port', 'account', 'password', 'reg_verify', 'notice', 'task_remind_hours', 'task_remind_hours2'])
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function setting__email()
|
||||
{
|
||||
User::auth('admin');
|
||||
//
|
||||
$type = trim(Request::input('type'));
|
||||
if ($type == 'save') {
|
||||
if (env("SYSTEM_SETTING") == 'disabled') {
|
||||
return Base::retError('当前环境禁止修改');
|
||||
}
|
||||
$all = Request::input();
|
||||
foreach ($all as $key => $value) {
|
||||
if (!in_array($key, [
|
||||
'smtp_server',
|
||||
'port',
|
||||
'account',
|
||||
'password',
|
||||
'reg_verify',
|
||||
'notice',
|
||||
'task_remind_hours',
|
||||
'task_remind_hours2'
|
||||
])) {
|
||||
unset($all[$key]);
|
||||
}
|
||||
}
|
||||
$setting = Base::setting('emailSetting', Base::newTrim($all));
|
||||
} else {
|
||||
$setting = Base::setting('emailSetting');
|
||||
}
|
||||
//
|
||||
$setting['smtp_server'] = $setting['smtp_server'] ?: '';
|
||||
$setting['port'] = $setting['port'] ?: '';
|
||||
$setting['account'] = $setting['account'] ?: '';
|
||||
$setting['password'] = $setting['password'] ?: '';
|
||||
$setting['reg_verify'] = $setting['reg_verify'] ?: 'close';
|
||||
$setting['notice'] = $setting['notice'] ?: 'open';
|
||||
$setting['task_remind_hours'] = floatval($setting['task_remind_hours']) ?: 0;
|
||||
$setting['task_remind_hours2'] = floatval($setting['task_remind_hours2']) ?: 0;
|
||||
//
|
||||
return Base::retSuccess('success', $setting ?: json_decode('{}'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/demo 03. 获取演示帐号
|
||||
* @api {get} api/system/demo 02. 获取演示账号
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
@@ -170,16 +82,12 @@ class SystemController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} api/system/priority 04. 任务优先级
|
||||
* @api {post} api/system/priority 03. 获取优先级、保存优先级
|
||||
*
|
||||
* @apiDescription 获取任务优先级、保存任务优先级
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName priority
|
||||
*
|
||||
* @apiParam {String} type
|
||||
* - get: 获取(默认)
|
||||
* - save: 保存(限管理员)
|
||||
* @apiParam {Array} list 优先级数据,格式:[{name,color,days,priority}]
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
@@ -197,7 +105,7 @@ class SystemController extends AbstractController
|
||||
return Base::retError('参数错误');
|
||||
}
|
||||
foreach ($list AS $item) {
|
||||
if (empty($item['name']) || empty($item['color']) || empty($item['priority'])) {
|
||||
if (empty($item['name']) || empty($item['color']) || empty($item['days']) || empty($item['priority'])) {
|
||||
continue;
|
||||
}
|
||||
$array[] = [
|
||||
@@ -219,54 +127,7 @@ class SystemController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} api/system/column/template 05. 创建项目模板
|
||||
*
|
||||
* @apiDescription 获取创建项目模板、保存创建项目模板
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName column__template
|
||||
*
|
||||
* @apiParam {String} type
|
||||
* - get: 获取(默认)
|
||||
* - save: 保存(限管理员)
|
||||
* @apiParam {Array} list 优先级数据,格式:[{name,columns}]
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function column__template()
|
||||
{
|
||||
$type = trim(Request::input('type'));
|
||||
if ($type == 'save') {
|
||||
User::auth('admin');
|
||||
$list = Base::getPostValue('list');
|
||||
$array = [];
|
||||
if (empty($list) || !is_array($list)) {
|
||||
return Base::retError('参数错误');
|
||||
}
|
||||
foreach ($list AS $item) {
|
||||
if (empty($item['name']) || empty($item['columns'])) {
|
||||
continue;
|
||||
}
|
||||
$array[] = [
|
||||
'name' => $item['name'],
|
||||
'columns' => array_values(array_filter(array_unique(explode(",", $item['columns']))))
|
||||
];
|
||||
}
|
||||
if (empty($array)) {
|
||||
return Base::retError('参数为空');
|
||||
}
|
||||
$setting = Base::setting('columnTemplate', $array);
|
||||
} else {
|
||||
$setting = Base::setting('columnTemplate');
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('success', $setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/get/info 06. 获取终端详细信息
|
||||
* @api {get} api/system/get/info 04. 获取终端详细信息
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
@@ -295,7 +156,7 @@ class SystemController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/get/ip 07. 获取IP地址
|
||||
* @api {get} api/system/get/ip 05. 获取IP地址
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
@@ -310,7 +171,7 @@ class SystemController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/get/cnip 08. 是否中国IP地址
|
||||
* @api {get} api/system/get/cnip 06. 是否中国IP地址
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
@@ -327,7 +188,7 @@ class SystemController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/get/ipgcj02 09. 获取IP地址经纬度
|
||||
* @api {get} api/system/get/ipgcj02 07. 获取IP地址经纬度
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
@@ -344,7 +205,7 @@ class SystemController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/get/ipinfo 10. 获取IP地址详细信息
|
||||
* @api {get} api/system/get/ipinfo 08. 获取IP地址详细信息
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
@@ -360,6 +221,89 @@ class SystemController extends AbstractController
|
||||
return Base::getIpInfo(Request::input("ip"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/get/appinfo 09. 获取应用下载信息
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName get__appinfo
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function get__appinfo() {
|
||||
$array = [
|
||||
'name' => '',
|
||||
'version' => '',
|
||||
'list' => [],
|
||||
];
|
||||
//
|
||||
$files = [
|
||||
base_path("package.json"),
|
||||
base_path("electron/package.json")
|
||||
];
|
||||
$dist = base_path("electron/dist");
|
||||
foreach ($files as $file) {
|
||||
if (file_exists($file)) {
|
||||
$packageArray = json_decode(file_get_contents($file), true);
|
||||
$array['name'] = $packageArray['name'] ?? 'No app';
|
||||
$array['version'] = $packageArray['version'] ?? '';
|
||||
//
|
||||
$list = [
|
||||
[
|
||||
'icon' => 'logo-apple',
|
||||
'name' => 'macOS Intel',
|
||||
'file' => "{$array['name']}-{$array['version']}.dmg"
|
||||
],
|
||||
[
|
||||
'icon' => 'logo-apple',
|
||||
'name' => 'macOS M1',
|
||||
'file' => "{$array['name']}-{$array['version']}-arm64.dmg"
|
||||
],
|
||||
[
|
||||
'icon' => 'logo-windows',
|
||||
'name' => 'Windows x64',
|
||||
'file' => "{$array['name']} Setup {$array['version']}.exe"
|
||||
]
|
||||
];
|
||||
foreach ($list as $item) {
|
||||
if (file_exists("{$dist}/{$item['file']}")) {
|
||||
$item['url'] = Base::fillUrl('api/system/get/appdown?file=' . urlencode($item['file']));
|
||||
$item['size'] = filesize("{$dist}/{$item['file']}");
|
||||
$array['list'][] = $item;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($array['list']) > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
if (count($array['list']) == 0) {
|
||||
return Base::retError('No file');
|
||||
}
|
||||
return Base::retSuccess('success', $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/get/appdown 10. 下载应用
|
||||
*
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName get__appdown
|
||||
*
|
||||
* @apiParam {String} file 文件名称
|
||||
*/
|
||||
public function get__appdown() {
|
||||
$file = Request::input("file");
|
||||
$path = base_path("electron/dist/" . $file);
|
||||
if (!file_exists($path)) {
|
||||
return Base::ajaxError("No file");
|
||||
}
|
||||
return Response::download($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} api/system/imgupload 11. 上传图片
|
||||
*
|
||||
@@ -368,15 +312,8 @@ class SystemController extends AbstractController
|
||||
* @apiGroup system
|
||||
* @apiName imgupload
|
||||
*
|
||||
* @apiParam {File} image post-图片对象
|
||||
* @apiParam {String} [image64] post-图片base64(与'image'二选一)
|
||||
* @apiParam {String} filename post-文件名
|
||||
* @apiParam {Number} [width] 压缩图片宽(默认0)
|
||||
* @apiParam {Number} [height] 压缩图片高(默认0)
|
||||
* @apiParam {String} [whcut] 压缩方式
|
||||
* - 1:裁切(默认,宽、高非0有效)
|
||||
* - 0:缩放
|
||||
* - -1或'auto':保持等比裁切
|
||||
* @apiParam {String} image64 图片base64
|
||||
* @apiParam {String} filename 文件名
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@@ -387,14 +324,11 @@ class SystemController extends AbstractController
|
||||
if (User::userid() === 0) {
|
||||
return Base::retError('身份失效,等重新登录');
|
||||
}
|
||||
$width = intval(Request::input('width'));
|
||||
$height = intval(Request::input('height'));
|
||||
$whcut = intval(Request::input('whcut', 1));
|
||||
$scale = [2160, 4160, -1];
|
||||
if ($width > 0 || $height > 0) {
|
||||
$scale = [$width, $height, $whcut];
|
||||
$scale = [intval(Request::input('width')), intval(Request::input('height'))];
|
||||
if (!$scale[0] && !$scale[1]) {
|
||||
$scale = [2160, 4160, -1];
|
||||
}
|
||||
$path = "uploads/user/picture/" . User::userid() . "/" . date("Ym") . "/";
|
||||
$path = "uploads/picture/" . User::userid() . "/" . date("Ym") . "/";
|
||||
$image64 = trim(Base::getPostValue('image64'));
|
||||
$fileName = trim(Base::getPostValue('filename'));
|
||||
if ($image64) {
|
||||
@@ -439,7 +373,7 @@ class SystemController extends AbstractController
|
||||
if (User::userid() === 0) {
|
||||
return Base::retError('身份失效,等重新登录');
|
||||
}
|
||||
$publicPath = "uploads/user/picture/" . User::userid() . "/";
|
||||
$publicPath = "uploads/picture/" . User::userid() . "/";
|
||||
$dirPath = public_path($publicPath);
|
||||
$dirs = $files = [];
|
||||
//
|
||||
@@ -537,7 +471,7 @@ class SystemController extends AbstractController
|
||||
if (User::userid() === 0) {
|
||||
return Base::retError('身份失效,等重新登录');
|
||||
}
|
||||
$path = "uploads/user/file/" . User::userid() . "/" . date("Ym") . "/";
|
||||
$path = "uploads/files/" . User::userid() . "/" . date("Ym") . "/";
|
||||
$image64 = trim(Base::getPostValue('image64'));
|
||||
$fileName = trim(Base::getPostValue('filename'));
|
||||
if ($image64) {
|
||||
@@ -557,66 +491,4 @@ class SystemController extends AbstractController
|
||||
//
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/get/starthome 14. 启动首页设置信息
|
||||
*
|
||||
* @apiDescription 用于判断注册是否需要启动首页
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName get__starthome
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function get__starthome()
|
||||
{
|
||||
return Base::retSuccess('success', [
|
||||
'need_start' => Base::settingFind('system', 'start_home') == 'open',
|
||||
'home_footer' => Base::settingFind('system', 'home_footer')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/system/email/check 15. 邮件发送测试(限管理员)
|
||||
*
|
||||
* @apiDescription 测试配置邮箱是否能发送邮件
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup system
|
||||
* @apiName email__check
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function email__check()
|
||||
{
|
||||
User::auth('admin');
|
||||
//
|
||||
$all = Request::input();
|
||||
if (!Base::isEmail($all['to'])) {
|
||||
return Base::retError('请输入正确的收件人地址');
|
||||
}
|
||||
try {
|
||||
Factory::mailer()
|
||||
->setDsn("smtp://{$all['account']}:{$all['password']}@{$all['smtp_server']}:{$all['port']}?verify_peer=0")
|
||||
->setMessage(EmailMessage::create()
|
||||
->from(env('APP_NAME', 'Task') . " <{$all['account']}>")
|
||||
->to($all['to'])
|
||||
->subject('Mail sending test')
|
||||
->html('<p>收到此电子邮件意味着您的邮箱配置正确。</p><p>Receiving this email means that your mailbox is configured correctly.</p>'))
|
||||
->send();
|
||||
return Base::retSuccess('成功发送');
|
||||
} catch (\Exception $e) {
|
||||
// 一般是请求超时
|
||||
if (str_contains($e->getMessage(), "Timed Out")) {
|
||||
return Base::retError("language.TimedOut");
|
||||
} elseif ($e->getCode() === 550) {
|
||||
return Base::retError('邮件内容被拒绝,请检查邮箱是否开启接收功能');
|
||||
} else {
|
||||
return Base::retError($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Models\AbstractModel;
|
||||
use App\Models\User;
|
||||
use App\Models\UserEmailVerification;
|
||||
use App\Models\UserTransfer;
|
||||
use App\Module\Base;
|
||||
use Arr;
|
||||
use Cache;
|
||||
@@ -34,7 +31,7 @@ class UsersController extends AbstractController
|
||||
* @apiParam {String} email 邮箱
|
||||
* @apiParam {String} password 密码
|
||||
* @apiParam {String} [code] 登录验证码
|
||||
* @apiParam {String} [invite] 注册邀请码
|
||||
* @apiParam {String} [key] 登陆验证码key
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@@ -45,56 +42,49 @@ class UsersController extends AbstractController
|
||||
$type = trim(Request::input('type'));
|
||||
$email = trim(Request::input('email'));
|
||||
$password = trim(Request::input('password'));
|
||||
$isRegVerify = Base::settingFind('emailSetting', 'reg_verify') === 'open';
|
||||
if ($type == 'reg') {
|
||||
$setting = Base::setting('system');
|
||||
if ($setting['reg'] == 'close') {
|
||||
return Base::retError('未开放注册');
|
||||
} elseif ($setting['reg'] == 'invite') {
|
||||
$invite = trim(Request::input('invite'));
|
||||
if (empty($invite) || $invite != $setting['reg_invite']) {
|
||||
return Base::retError('请输入正确的邀请码');
|
||||
}
|
||||
}
|
||||
$user = User::reg($email, $password);
|
||||
if ($isRegVerify) {
|
||||
UserEmailVerification::userEmailSend($user);
|
||||
return Base::retError('注册成功,请验证邮箱后登录', ['code' => 'email']);
|
||||
}
|
||||
} else {
|
||||
$needCode = !Base::isError(User::needCode($email));
|
||||
if ($needCode) {
|
||||
$code = trim(Request::input('code'));
|
||||
$key = trim(Request::input('key'));
|
||||
if (empty($code)) {
|
||||
return Base::retError('请输入验证码', ['code' => 'need']);
|
||||
}
|
||||
if (!Captcha::check($code)) {
|
||||
return Base::retError('请输入正确的验证码', ['code' => 'need']);
|
||||
if (empty($key)) {
|
||||
if (!Captcha::check($code)) {
|
||||
return Base::retError('请输入正确的验证码', ['code' => 'need']);
|
||||
}
|
||||
} else {
|
||||
if (!Captcha::check_api($code, $key)) {
|
||||
return Base::retError('请输入正确的验证码', ['code' => 'need']);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
$retError = function ($msg) use ($email) {
|
||||
Cache::forever("code::" . $email, "need");
|
||||
$needCode = !Base::isError(User::needCode($email));
|
||||
$needData = ['code' => $needCode ? 'need' : 'no'];
|
||||
$needData = [ 'code' => $needCode ? 'need' : 'no' ];
|
||||
return Base::retError($msg, $needData);
|
||||
};
|
||||
$user = User::whereEmail($email)->first();
|
||||
if (empty($user)) {
|
||||
return $retError('帐号或密码错误');
|
||||
return $retError('账号或密码错误');
|
||||
}
|
||||
if ($user->password != Base::md52($password, $user->encrypt)) {
|
||||
return $retError('帐号或密码错误');
|
||||
return $retError('账号或密码错误');
|
||||
}
|
||||
//
|
||||
if (in_array('disable', $user->identity)) {
|
||||
return $retError('帐号已停用...');
|
||||
}
|
||||
Cache::forget("code::" . $email);
|
||||
if ($isRegVerify && $user->email_verity === 0) {
|
||||
UserEmailVerification::userEmailSend($user);
|
||||
return Base::retError('您还没有验证邮箱,请先登录邮箱通过验证邮件验证邮箱', ['code' => 'email']);
|
||||
}
|
||||
}
|
||||
//
|
||||
$array = [
|
||||
@@ -137,6 +127,8 @@ class UsersController extends AbstractController
|
||||
* @apiGroup users
|
||||
* @apiName login__codeimg
|
||||
*
|
||||
* @apiParam {String} email 用户名
|
||||
*
|
||||
* @apiSuccess {Image} data 返回数据(直接输出图片)
|
||||
*/
|
||||
public function login__codeimg()
|
||||
@@ -163,26 +155,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/reg/needinvite 05. 是否需要邀请码
|
||||
*
|
||||
* @apiDescription 用于判断注册是否需要邀请码
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup users
|
||||
* @apiName reg__needinvite
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function reg__needinvite()
|
||||
{
|
||||
return Base::retSuccess('success', [
|
||||
'need' => Base::settingFind('system', 'reg') == 'invite'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/info 06. 获取我的信息
|
||||
* @api {get} api/users/info 05. 获取我的信息
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -214,13 +187,11 @@ class UsersController extends AbstractController
|
||||
$user = User::auth();
|
||||
User::token($user);
|
||||
//
|
||||
$data = $user->toArray();
|
||||
$data['nickname_original'] = $user->getRawOriginal('nickname');
|
||||
return Base::retSuccess('success', $data);
|
||||
return Base::retSuccess('success', $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/editdata 07. 修改自己的资料
|
||||
* @api {get} api/users/editdata 06. 修改自己的资料
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -247,13 +218,13 @@ class UsersController extends AbstractController
|
||||
$userimg = is_array($userimg) ? $userimg[0]['path'] : $userimg;
|
||||
$user->userimg = Base::unFillUrl($userimg);
|
||||
} else {
|
||||
$user->userimg = $user->getUserimgAttribute(null);
|
||||
$user->userimg = '';
|
||||
}
|
||||
}
|
||||
//昵称
|
||||
if (Arr::exists($data, 'nickname')) {
|
||||
$nickname = trim(Request::input('nickname'));
|
||||
if ($nickname && mb_strlen($nickname) < 2) {
|
||||
if (mb_strlen($nickname) < 2) {
|
||||
return Base::retError('昵称不可以少于2个字');
|
||||
} elseif (mb_strlen($nickname) > 20) {
|
||||
return Base::retError('昵称最多只能设置20个字');
|
||||
@@ -264,7 +235,7 @@ class UsersController extends AbstractController
|
||||
//职位/职称
|
||||
if (Arr::exists($data, 'profession')) {
|
||||
$profession = trim(Request::input('profession'));
|
||||
if ($profession && mb_strlen($profession) < 2) {
|
||||
if (mb_strlen($profession) < 2) {
|
||||
return Base::retError('职位/职称不可以少于2个字');
|
||||
} elseif (mb_strlen($profession) > 20) {
|
||||
return Base::retError('职位/职称最多只能设置20个字');
|
||||
@@ -280,7 +251,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/editpass 08. 修改自己的密码
|
||||
* @api {get} api/users/editpass 07. 修改自己的密码
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -320,7 +291,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/search 09. 搜索会员列表
|
||||
* @api {get} api/users/search 08. 搜索会员列表
|
||||
*
|
||||
* @apiDescription 搜索会员列表
|
||||
* @apiVersion 1.0.0
|
||||
@@ -328,12 +299,11 @@ class UsersController extends AbstractController
|
||||
* @apiName searchinfo
|
||||
*
|
||||
* @apiParam {Object} keys 搜索条件
|
||||
* - keys.key 昵称、邮箱关键字
|
||||
* - keys.disable 0-排除禁止(默认),1-含禁止,2-仅禁止
|
||||
* - keys.key 昵称、邮箱
|
||||
* - keys.project_id 在指定项目ID
|
||||
* - keys.no_project_id 不在指定项目ID
|
||||
* @apiParam {Object} sorts 排序方式
|
||||
* - sorts.az 按字母:asc|desc
|
||||
* - sorts.az 字母
|
||||
*
|
||||
* @apiParam {Number} [take] 获取数量,10-100
|
||||
* @apiParam {Number} [page] 当前页,默认:1(赋值分页模式,take参数无效)
|
||||
@@ -349,32 +319,28 @@ class UsersController extends AbstractController
|
||||
//
|
||||
$keys = Request::input('keys');
|
||||
$sorts = Request::input('sorts');
|
||||
$keys = is_array($keys) ? $keys : [];
|
||||
$sorts = is_array($sorts) ? $sorts : [];
|
||||
//
|
||||
if ($keys['key']) {
|
||||
$builder->where(function($query) use ($keys) {
|
||||
$query->where("email", "like", "%{$keys['key']}%")
|
||||
->orWhere("nickname", "like", "%{$keys['key']}%");
|
||||
});
|
||||
if (is_array($keys)) {
|
||||
if ($keys['key']) {
|
||||
$builder->where(function($query) use ($keys) {
|
||||
$query->where("email", "like", "%{$keys['key']}%")
|
||||
->orWhere("nickname", "like", "%{$keys['key']}%");
|
||||
});
|
||||
}
|
||||
if (intval($keys['project_id']) > 0) {
|
||||
$builder->whereIn('userid', function ($query) use ($keys) {
|
||||
$query->select('userid')->from('project_users')->where('project_id', $keys['project_id']);
|
||||
});
|
||||
}
|
||||
if (intval($keys['no_project_id']) > 0) {
|
||||
$builder->whereNotIn('userid', function ($query) use ($keys) {
|
||||
$query->select('userid')->from('project_users')->where('project_id', $keys['no_project_id']);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (intval($keys['disable']) == 0) {
|
||||
$builder->whereNull("disable_at");
|
||||
} elseif (intval($keys['disable']) == 2) {
|
||||
$builder->whereNotNull("disable_at");
|
||||
}
|
||||
if (intval($keys['project_id']) > 0) {
|
||||
$builder->whereIn('userid', function ($query) use ($keys) {
|
||||
$query->select('userid')->from('project_users')->where('project_id', $keys['project_id']);
|
||||
});
|
||||
}
|
||||
if (intval($keys['no_project_id']) > 0) {
|
||||
$builder->whereNotIn('userid', function ($query) use ($keys) {
|
||||
$query->select('userid')->from('project_users')->where('project_id', $keys['no_project_id']);
|
||||
});
|
||||
}
|
||||
if (in_array($sorts['az'], ['asc', 'desc'])) {
|
||||
$builder->orderBy('az', $sorts['az']);
|
||||
if (is_array($sorts)) {
|
||||
if (in_array($sorts['az'], ['asc', 'desc'])) {
|
||||
$builder->orderBy('az', $sorts['az']);
|
||||
}
|
||||
}
|
||||
//
|
||||
if (Request::exists('page')) {
|
||||
@@ -386,7 +352,7 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/basic 10. 获取指定会员基础信息
|
||||
* @api {get} api/users/basic 09. 获取指定会员基础信息
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
@@ -420,34 +386,14 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/lists 11. 会员列表(限管理员)
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup users
|
||||
* @apiName lists
|
||||
* 会员列表(限管理员)
|
||||
*
|
||||
* @apiParam {Object} [keys] 搜索条件
|
||||
* - keys.key 邮箱/昵称/职位(赋值后keys.email、keys.nickname、keys.profession失效)
|
||||
* - keys.email 邮箱
|
||||
* - keys.nickname 昵称
|
||||
* - keys.profession 职位
|
||||
* - keys.identity 身份(如:admin、noadmin)
|
||||
* - keys.disable 是否离职
|
||||
* - yes: 仅离职
|
||||
* - all: 全部
|
||||
* - 其他值: 仅在职(默认)
|
||||
* - keys.email_verity 邮箱是否认证
|
||||
* - yes: 已认证
|
||||
* - no: 未认证
|
||||
* - 其他值: 全部(默认)
|
||||
*
|
||||
* @apiParam {Number} [page] 当前页,默认:1
|
||||
* @apiParam {Number} [pagesize] 每页显示数量,默认:20,最大:50
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
*/
|
||||
public function lists()
|
||||
{
|
||||
@@ -457,26 +403,14 @@ class UsersController extends AbstractController
|
||||
//
|
||||
$keys = Request::input('keys');
|
||||
if (is_array($keys)) {
|
||||
if ($keys['key']) {
|
||||
if (str_contains($keys['key'], "@")) {
|
||||
$builder->where("email", "like", "%{$keys['key']}%");
|
||||
} else {
|
||||
$builder->where(function($query) use ($keys) {
|
||||
$query->where("email", "like", "%{$keys['key']}%")
|
||||
->orWhere("nickname", "like", "%{$keys['key']}%")
|
||||
->orWhere("profession", "like", "%{$keys['key']}%");
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if ($keys['email']) {
|
||||
$builder->where("email", "like", "%{$keys['email']}%");
|
||||
}
|
||||
if ($keys['nickname']) {
|
||||
$builder->where("nickname", "like", "%{$keys['nickname']}%");
|
||||
}
|
||||
if ($keys['profession']) {
|
||||
$builder->where("profession", "like", "%{$keys['profession']}%");
|
||||
}
|
||||
if ($keys['email']) {
|
||||
$builder->where("email", "like", "%{$keys['email']}%");
|
||||
}
|
||||
if ($keys['nickname']) {
|
||||
$builder->where("nickname", "like", "%{$keys['nickname']}%");
|
||||
}
|
||||
if ($keys['profession']) {
|
||||
$builder->where("profession", "like", "%{$keys['profession']}%");
|
||||
}
|
||||
if ($keys['identity']) {
|
||||
if (Base::leftExists($keys['identity'], "no")) {
|
||||
@@ -485,18 +419,6 @@ class UsersController extends AbstractController
|
||||
$builder->where("identity", "like", "%,{$keys['identity']},%");
|
||||
}
|
||||
}
|
||||
if ($keys['disable'] === 'yes') {
|
||||
$builder->whereNotNull('disable_at');
|
||||
} elseif ($keys['disable'] !== 'all') {
|
||||
$builder->whereNull('disable_at');
|
||||
}
|
||||
if ($keys['email_verity'] === 'yes') {
|
||||
$builder->whereEmailVerity(1);
|
||||
} elseif ($keys['email_verity'] === 'no') {
|
||||
$builder->whereEmailVerity(0);
|
||||
}
|
||||
} else {
|
||||
$builder->whereNull('disable_at');
|
||||
}
|
||||
$list = $builder->orderByDesc('userid')->paginate(Base::getPaginate(50, 20));
|
||||
//
|
||||
@@ -504,33 +426,22 @@ class UsersController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/operation 12. 操作会员(限管理员)
|
||||
* 操作会员(限管理员)
|
||||
*
|
||||
* @apiDescription 需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup users
|
||||
* @apiName operation
|
||||
*
|
||||
* @apiParam {Number} userid 会员ID
|
||||
* @apiParam {String} [type] 操作
|
||||
* @apiParam {Number} userid 会员ID
|
||||
* @apiParam {String} [type] 操作
|
||||
* - setadmin 设为管理员
|
||||
* - clearadmin 取消管理员
|
||||
* - setdisable 设为离职(需要参数 disable_time、transfer_userid)
|
||||
* - cleardisable 取消离职
|
||||
* - setdisable 设为禁用
|
||||
* - cleardisable 取消禁用
|
||||
* - delete 删除会员
|
||||
* @apiParam {String} [password] 新的密码
|
||||
* @apiParam {String} [nickname] 昵称
|
||||
* @apiParam {String} [profession] 职位
|
||||
* @apiParam {String} [disable_time] 离职时间
|
||||
* @apiParam {String} [transfer_userid] 离职交接人
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据
|
||||
* @apiParam {String} [password] 新的密码
|
||||
* @apiParam {String} [nickname] 昵称
|
||||
* @apiParam {String} [profession] 职位
|
||||
*/
|
||||
public function operation()
|
||||
{
|
||||
$user = User::auth('admin');
|
||||
User::auth('admin');
|
||||
//
|
||||
$data = Request::all();
|
||||
$userid = intval($data['userid']);
|
||||
@@ -543,7 +454,6 @@ class UsersController extends AbstractController
|
||||
$userInfo->checkSystem(1);
|
||||
//
|
||||
$upArray = [];
|
||||
$transferUser = null;
|
||||
switch ($type) {
|
||||
case 'setadmin':
|
||||
$upArray['identity'] = array_diff($userInfo->identity, ['admin']);
|
||||
@@ -555,35 +465,16 @@ class UsersController extends AbstractController
|
||||
break;
|
||||
|
||||
case 'setdisable':
|
||||
if ($userInfo->userid === $user->userid) {
|
||||
return Base::retError('不能操作自己离职');
|
||||
}
|
||||
$upArray['identity'] = array_diff($userInfo->identity, ['disable']);
|
||||
$upArray['identity'][] = 'disable';
|
||||
$upArray['disable_at'] = Carbon::parse($data['disable_time']);
|
||||
$transferUserid = is_array($data['transfer_userid']) ? $data['transfer_userid'][0] : $data['transfer_userid'];
|
||||
$transferUser = User::find(intval($transferUserid));
|
||||
if (empty($transferUser)) {
|
||||
return Base::retError('请选择正确的交接人');
|
||||
}
|
||||
if ($transferUser->userid === $userInfo->userid) {
|
||||
return Base::retError('不能移交给自己');
|
||||
}
|
||||
if (in_array('disable', $transferUser->identity)) {
|
||||
return Base::retError('交接人已离职,请选择另一个交接人');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'cleardisable':
|
||||
$upArray['identity'] = array_diff($userInfo->identity, ['disable']);
|
||||
$upArray['disable_at'] = null;
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
if ($userInfo->userid === $user->userid) {
|
||||
return Base::retError('不能删除自己');
|
||||
}
|
||||
$userInfo->deleteUser();
|
||||
$userInfo->delete();
|
||||
break;
|
||||
}
|
||||
if (isset($upArray['identity'])) {
|
||||
@@ -600,7 +491,7 @@ class UsersController extends AbstractController
|
||||
// 昵称
|
||||
if (Arr::exists($data, 'nickname')) {
|
||||
$nickname = trim($data['nickname']);
|
||||
if ($nickname && mb_strlen($nickname) < 2) {
|
||||
if (mb_strlen($nickname) < 2) {
|
||||
return Base::retError('昵称不可以少于2个字');
|
||||
} elseif (mb_strlen($nickname) > 20) {
|
||||
return Base::retError('昵称最多只能设置20个字');
|
||||
@@ -611,7 +502,7 @@ class UsersController extends AbstractController
|
||||
// 职位/职称
|
||||
if (Arr::exists($data, 'profession')) {
|
||||
$profession = trim($data['profession']);
|
||||
if ($profession && mb_strlen($profession) < 2) {
|
||||
if (mb_strlen($profession) < 2) {
|
||||
return Base::retError('职位/职称不可以少于2个字');
|
||||
} elseif (mb_strlen($profession) > 20) {
|
||||
return Base::retError('职位/职称最多只能设置20个字');
|
||||
@@ -620,68 +511,10 @@ class UsersController extends AbstractController
|
||||
}
|
||||
}
|
||||
if ($upArray) {
|
||||
AbstractModel::transaction(function() use ($type, $upArray, $userInfo, $transferUser) {
|
||||
$userInfo->updateInstance($upArray);
|
||||
$userInfo->save();
|
||||
if ($type === 'setdisable') {
|
||||
$userTransfer = UserTransfer::createInstance([
|
||||
'original_userid' => $userInfo->userid,
|
||||
'new_userid' => $transferUser->userid,
|
||||
]);
|
||||
$userTransfer->save();
|
||||
$userTransfer->start();
|
||||
}
|
||||
});
|
||||
$userInfo->updateInstance($upArray);
|
||||
$userInfo->save();
|
||||
}
|
||||
//
|
||||
return Base::retSuccess('修改成功', $userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} api/users/email/verification 13. 邮箱验证
|
||||
*
|
||||
* @apiDescription 不需要token身份
|
||||
* @apiVersion 1.0.0
|
||||
* @apiGroup users
|
||||
* @apiName email__verification
|
||||
*
|
||||
* @apiParam {String} code 验证参数
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
* @apiSuccess {Object} data 返回数据(同"获取我的信息"接口)
|
||||
*/
|
||||
public function email__verification()
|
||||
{
|
||||
$data = Request::input();
|
||||
// 表单验证
|
||||
Base::validator($data, [
|
||||
'code.required' => '验证码不能为空',
|
||||
]);
|
||||
//
|
||||
$res = UserEmailVerification::whereCode($data['code'])->first();
|
||||
if (empty($res)) {
|
||||
return Base::retError('无效连接,请重新注册');
|
||||
}
|
||||
|
||||
// 如果已经校验过
|
||||
if (intval($res->status) === 1)
|
||||
return Base::retError('链接已经使用过', ['code' => 2]);
|
||||
|
||||
$oldTime = Carbon::parse($res->created_at)->timestamp;
|
||||
$time = Base::Time();
|
||||
|
||||
// 30分钟失效
|
||||
if (abs($time - $oldTime) > 1800) {
|
||||
return Base::retError("链接已失效,请重新登录/注册");
|
||||
}
|
||||
UserEmailVerification::whereCode($data['code'])->update([
|
||||
'status' => 1
|
||||
]);
|
||||
User::whereUserid($res->userid)->update([
|
||||
'email_verity' => 1
|
||||
]);
|
||||
|
||||
return Base::retSuccess('绑定邮箱成功');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* 给apidoc项目增加顺序编号
|
||||
*/
|
||||
|
||||
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
|
||||
error_reporting(E_ALL & ~E_NOTICE);
|
||||
|
||||
$path = dirname(__FILE__). '/';
|
||||
$lists = scandir($path);
|
||||
|
||||
@@ -3,13 +3,9 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Module\Base;
|
||||
use App\Tasks\AutoArchivedTask;
|
||||
use App\Tasks\DeleteTmpTask;
|
||||
use App\Tasks\OverdueRemindEmailTask;
|
||||
use Arr;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use Redirect;
|
||||
use Request;
|
||||
|
||||
|
||||
/**
|
||||
@@ -25,10 +21,6 @@ class IndexController extends InvokeController
|
||||
if ($action) {
|
||||
$app .= "__" . $action;
|
||||
}
|
||||
if ($app === 'manifest.txt') {
|
||||
$app = 'manifest';
|
||||
$child = 'txt';
|
||||
}
|
||||
if (!method_exists($this, $app)) {
|
||||
$app = method_exists($this, $method) ? $method : 'main';
|
||||
}
|
||||
@@ -37,88 +29,11 @@ class IndexController extends InvokeController
|
||||
|
||||
/**
|
||||
* 首页
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function main()
|
||||
{
|
||||
$hash = 'no';
|
||||
$path = public_path('js/hash');
|
||||
$murl = url('manifest.txt');
|
||||
if (file_exists($path)) {
|
||||
$hash = trim(file_get_contents(public_path('js/hash')));
|
||||
if (strlen($hash) > 16) {
|
||||
$hash = 'long';
|
||||
}
|
||||
}
|
||||
return response()->view('main', [
|
||||
'version' => Base::getVersion(),
|
||||
'hash' => $hash
|
||||
])->header('Link', "<{$murl}>; 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.0.1-37/web-apps/vendor/requirejs/require.js",
|
||||
"office/7.0.1-37/web-apps/apps/api/documents/api.js",
|
||||
"office/7.0.1-37/sdkjs/common/AllFonts.js",
|
||||
"office/7.0.1-37/web-apps/vendor/xregexp/xregexp-all-min.js",
|
||||
"office/7.0.1-37/web-apps/vendor/sockjs/sockjs.min.js",
|
||||
"office/7.0.1-37/web-apps/vendor/jszip/jszip.min.js",
|
||||
"office/7.0.1-37/web-apps/vendor/jszip-utils/jszip-utils.min.js",
|
||||
"office/7.0.1-37/sdkjs/common/libfont/wasm/fonts.js",
|
||||
"office/7.0.1-37/sdkjs/common/Charts/ChartStyles.js",
|
||||
"office/7.0.1-37/sdkjs/slide/themes//themes.js",
|
||||
|
||||
"office/7.0.1-37/web-apps/apps/presentationeditor/main/app.js",
|
||||
"office/7.0.1-37/sdkjs/slide/sdk-all-min.js",
|
||||
"office/7.0.1-37/sdkjs/slide/sdk-all.js",
|
||||
|
||||
"office/7.0.1-37/web-apps/apps/documenteditor/main/app.js",
|
||||
"office/7.0.1-37/sdkjs/word/sdk-all-min.js",
|
||||
"office/7.0.1-37/sdkjs/word/sdk-all.js",
|
||||
|
||||
"office/7.0.1-37/web-apps/apps/spreadsheeteditor/main/app.js",
|
||||
"office/7.0.1-37/sdkjs/cell/sdk-all-min.js",
|
||||
"office/7.0.1-37/sdkjs/cell/sdk-all.js",
|
||||
];
|
||||
foreach ($array as &$item) {
|
||||
$item = url($item);
|
||||
}
|
||||
return implode(PHP_EOL, $array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本号
|
||||
* @return array
|
||||
*/
|
||||
public function version()
|
||||
{
|
||||
$url = url('');
|
||||
$package = Base::getPackage();
|
||||
$array = [
|
||||
'version' => Base::getVersion(),
|
||||
'publish' => Arr::get($package, 'app.0.publish'),
|
||||
];
|
||||
if (is_array($package['app'])) {
|
||||
foreach ($package['app'] as $item) {
|
||||
$urls = $item['urls'] && is_array($item['urls']) ? $item['urls'] : $item['url'];
|
||||
if (is_array($item['publish']) && Base::hostContrast($url, $urls)) {
|
||||
$array['publish'] = $item['publish'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
return view('main', ['version' => Base::getVersion()]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,71 +58,10 @@ class IndexController extends InvokeController
|
||||
// 删除过期的临时表数据
|
||||
Task::deliver(new DeleteTmpTask('wg_tmp_msgs', 1));
|
||||
Task::deliver(new DeleteTmpTask('tmp', 24));
|
||||
// 自动归档任务
|
||||
Task::deliver(new AutoArchivedTask());
|
||||
// 任务到期邮件提醒
|
||||
Task::deliver(new OverdueRemindEmailTask());
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
/**
|
||||
* 桌面客户端发布
|
||||
*/
|
||||
public function desktop__publish($name = '')
|
||||
{
|
||||
$latestFile = public_path("uploads/desktop/latest");
|
||||
$genericVersion = Request::header('generic-version');
|
||||
// 上传
|
||||
if (preg_match("/^\d+\.\d+\.\d+$/", $genericVersion)) {
|
||||
$latestVersion = file_exists($latestFile) ? trim(file_get_contents($latestFile)) : "0.0.1";
|
||||
if (version_compare($genericVersion, $latestVersion) > -1) { // 限制上传版本必须 ≥ 当前版本
|
||||
$genericPath = "uploads/desktop/{$genericVersion}/";
|
||||
$res = Base::upload([
|
||||
"file" => Request::file('file'),
|
||||
"type" => 'desktop',
|
||||
"path" => $genericPath,
|
||||
"fileName" => true
|
||||
]);
|
||||
if (Base::isSuccess($res)) {
|
||||
file_put_contents($latestFile, $genericVersion);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
// 列表
|
||||
if (preg_match("/^\d+\.\d+\.\d+$/", $name)) {
|
||||
$path = "uploads/desktop/{$name}";
|
||||
$dirPath = public_path($path);
|
||||
$lists = Base::readDir($dirPath);
|
||||
$files = [];
|
||||
foreach ($lists as $file) {
|
||||
if (str_ends_with($file, '.yml') || str_ends_with($file, '.yaml')) {
|
||||
continue;
|
||||
}
|
||||
$fileName = Base::leftDelete($file, $dirPath);
|
||||
$files[] = [
|
||||
'name' => substr($fileName, 1),
|
||||
'time' => date("Y-m-d H:i:s", fileatime($file)),
|
||||
'size' => Base::readableBytes(filesize($file)),
|
||||
'url' => Base::fillUrl($path . $fileName),
|
||||
];
|
||||
}
|
||||
return view('desktop', ['version' => $name, 'files' => $files]);
|
||||
}
|
||||
// 下载
|
||||
if ($name && file_exists($latestFile)) {
|
||||
$genericVersion = file_get_contents($latestFile);
|
||||
if (preg_match("/^\d+\.\d+\.\d+$/", $genericVersion)) {
|
||||
$filePath = public_path("uploads/desktop/{$genericVersion}/{$name}");
|
||||
if (file_exists($filePath)) {
|
||||
return response()->download($filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
return abort(404);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取所有中文
|
||||
* @return array|string
|
||||
|
||||
@@ -21,20 +21,14 @@ class VerifyCsrfToken extends Middleware
|
||||
// 保存任务优先级
|
||||
'api/system/priority/',
|
||||
|
||||
// 保存创建项目列表模板
|
||||
'api/system/column/template/',
|
||||
|
||||
// 添加任务
|
||||
'api/project/task/add/',
|
||||
|
||||
// 保存工作流
|
||||
'api/project/flow/save/',
|
||||
|
||||
// 修改任务
|
||||
'api/project/task/update/',
|
||||
|
||||
// 聊天发文本
|
||||
'api/dialog/msg/sendtext/',
|
||||
// 上传任务问题
|
||||
'api/project/task/upload/',
|
||||
|
||||
// 聊天发文件
|
||||
'api/dialog/msg/sendfile/',
|
||||
@@ -47,11 +41,5 @@ class VerifyCsrfToken extends Middleware
|
||||
|
||||
// 保存文件内容(上传)
|
||||
'api/file/content/upload/',
|
||||
|
||||
// 保存汇报
|
||||
'api/report/store/',
|
||||
|
||||
// 发布桌面端
|
||||
'desktop/publish/',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -10,15 +10,13 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* App\Models\AbstractModel
|
||||
* App\Model\AbstractModel
|
||||
*
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel saveOrIgnore()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AbstractModel getKeyValue()
|
||||
* @method static \Illuminate\Database\Eloquent\Model|object|static|null cancelAppend()
|
||||
* @method static \Illuminate\Database\Eloquent\Model|object|static|null cancelHidden()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|static with($relations)
|
||||
* @method static \Illuminate\Database\Query\Builder|static select($columns = [])
|
||||
* @method static \Illuminate\Database\Query\Builder|static whereNotIn($column, $values, $boolean = 'and')
|
||||
@@ -64,24 +62,6 @@ class AbstractModel extends Model
|
||||
return $this->$key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消附加值
|
||||
* @return static
|
||||
*/
|
||||
protected function scopeCancelAppend()
|
||||
{
|
||||
return $this->setAppends([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消隐藏值
|
||||
* @return static
|
||||
*/
|
||||
protected function scopeCancelHidden()
|
||||
{
|
||||
return $this->setHidden([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为数组 / JSON 序列化准备日期。
|
||||
* @param DateTimeInterface $date
|
||||
@@ -153,23 +133,16 @@ class AbstractModel extends Model
|
||||
* @param $where
|
||||
* @param array $update 存在时更新的内容
|
||||
* @param array $insert 不存在时插入的内容,如果没有则插入更新内容
|
||||
* @param bool $isInsert 是否是插入数据
|
||||
* @return AbstractModel|\Illuminate\Database\Eloquent\Builder|Model|object|static|null
|
||||
*/
|
||||
public static function updateInsert($where, $update = [], $insert = [], &$isInsert = true)
|
||||
public static function updateInsert($where, $update = [], $insert = [])
|
||||
{
|
||||
$row = static::where($where)->first();
|
||||
if (empty($row)) {
|
||||
$row = new static;
|
||||
$array = array_merge($where, $insert ?: $update);
|
||||
if (isset($array[$row->primaryKey])) {
|
||||
unset($array[$row->primaryKey]);
|
||||
}
|
||||
$row->updateInstance($array);
|
||||
$isInsert = true;
|
||||
$row->updateInstance(array_merge($where, $insert ?: $update));
|
||||
} elseif ($update) {
|
||||
$row->updateInstance($update);
|
||||
$isInsert = false;
|
||||
}
|
||||
if (!$row->save()) {
|
||||
return null;
|
||||
|
||||
@@ -13,7 +13,6 @@ use Request;
|
||||
* App\Models\File
|
||||
*
|
||||
* @property int $id
|
||||
* @property string|null $pids 上级ID递归
|
||||
* @property int|null $pid 上级ID
|
||||
* @property int|null $cid 复制ID
|
||||
* @property string|null $name 名称
|
||||
@@ -38,7 +37,6 @@ use Request;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File whereName($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File wherePid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File wherePids($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File whereShare($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File whereSize($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|File whereType($value)
|
||||
@@ -53,68 +51,43 @@ class File extends AbstractModel
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
* 文件文件
|
||||
* 是否有访问权限(没有时抛出异常)
|
||||
* @param $userid
|
||||
*/
|
||||
const codeExt = [
|
||||
'txt',
|
||||
'htaccess', 'htgroups', 'htpasswd', 'conf', 'bat', 'cmd', 'cpp', 'c', 'cc', 'cxx', 'h', 'hh', 'hpp', 'ino', 'cs', 'css',
|
||||
'dockerfile', 'go', 'golang', 'html', 'htm', 'xhtml', 'vue', 'we', 'wpy', 'java', 'js', 'jsm', 'jsx', 'json', 'jsp', 'less', 'lua', 'makefile', 'gnumakefile',
|
||||
'ocamlmakefile', 'make', 'mysql', 'nginx', 'ini', 'cfg', 'prefs', 'm', 'mm', 'pl', 'pm', 'p6', 'pl6', 'pm6', 'pgsql', 'php',
|
||||
'inc', 'phtml', 'shtml', 'php3', 'php4', 'php5', 'phps', 'phpt', 'aw', 'ctp', 'module', 'ps1', 'py', 'r', 'rb', 'ru', 'gemspec', 'rake', 'guardfile', 'rakefile',
|
||||
'gemfile', 'rs', 'sass', 'scss', 'sh', 'bash', 'bashrc', 'sql', 'sqlserver', 'swift', 'ts', 'typescript', 'str', 'vbs', 'vb', 'v', 'vh', 'sv', 'svh', 'xml',
|
||||
'rdf', 'rss', 'wsdl', 'xslt', 'atom', 'mathml', 'mml', 'xul', 'xbl', 'xaml', 'yaml', 'yml',
|
||||
'asp', 'properties', 'gitignore', 'log', 'bas', 'prg', 'python', 'ftl', 'aspx'
|
||||
];
|
||||
|
||||
/**
|
||||
* office文件
|
||||
*/
|
||||
const officeExt = [
|
||||
'doc', 'docx',
|
||||
'xls', 'xlsx',
|
||||
'ppt', 'pptx',
|
||||
];
|
||||
|
||||
/**
|
||||
* 图片文件
|
||||
*/
|
||||
const imageExt = [
|
||||
'jpg', 'jpeg', 'png', 'gif', 'bmp'
|
||||
];
|
||||
|
||||
/**
|
||||
* 本地媒体文件
|
||||
*/
|
||||
const localExt = [
|
||||
'jpg', 'jpeg', 'png', 'gif', 'bmp', 'ico', 'raw',
|
||||
'tif', 'tiff',
|
||||
'mp3', 'wav', 'mp4', 'flv',
|
||||
'avi', 'mov', 'wmv', 'mkv', '3gp', 'rm',
|
||||
];
|
||||
public function exceAllow($userid)
|
||||
{
|
||||
if (!$this->chackAllow($userid)) {
|
||||
throw new ApiException('没有访问权限');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否有访问权限
|
||||
* ① 自己的文件夹
|
||||
* ② 共享所有人的文件夹
|
||||
* ③ 在指定共享人员内
|
||||
* @param $userid
|
||||
* @return int -1:没有权限,0:访问权限,1:读写权限,1000:所有者或创建者
|
||||
* @return bool
|
||||
*/
|
||||
public function getPermission($userid)
|
||||
public function chackAllow($userid)
|
||||
{
|
||||
if ($userid == $this->userid || $userid == $this->created_id) {
|
||||
// ① 自己的文件夹 或 自己创建的文件夹
|
||||
return 1000;
|
||||
if ($userid == $this->userid) {
|
||||
// ① 自己的文件夹
|
||||
return true;
|
||||
}
|
||||
$row = $this->getShareInfo();
|
||||
if ($row) {
|
||||
$fileUser = FileUser::whereFileId($row->id)->where(function ($query) use ($userid) {
|
||||
$query->where('userid', 0);
|
||||
$query->orWhere('userid', $userid);
|
||||
})->orderByDesc('permission')->first();
|
||||
if ($fileUser) {
|
||||
// ② 在指定共享成员内
|
||||
return $fileUser->permission;
|
||||
if ($row->share == 1) {
|
||||
// ② 共享所有人的文件夹
|
||||
return true;
|
||||
} elseif ($row->share == 2) {
|
||||
// ③ 在指定共享人员内
|
||||
if (FileUser::whereFileId($row->id)->whereUserid($userid)->exists()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,7 +96,7 @@ class File extends AbstractModel
|
||||
*/
|
||||
public function getShareInfo()
|
||||
{
|
||||
if ($this->share) {
|
||||
if ($this->share > 0) {
|
||||
return $this;
|
||||
}
|
||||
$pid = $this->pid;
|
||||
@@ -132,7 +105,7 @@ class File extends AbstractModel
|
||||
if (empty($row)) {
|
||||
break;
|
||||
}
|
||||
if ($row->share) {
|
||||
if ($row->share > 0) {
|
||||
return $row;
|
||||
}
|
||||
$pid = $row->pid;
|
||||
@@ -142,7 +115,7 @@ class File extends AbstractModel
|
||||
|
||||
/**
|
||||
* 是否处于共享文件夹内(不含自身)
|
||||
* @return File|false
|
||||
* @return bool
|
||||
*/
|
||||
public function isNnShare()
|
||||
{
|
||||
@@ -152,8 +125,8 @@ class File extends AbstractModel
|
||||
if (empty($row)) {
|
||||
break;
|
||||
}
|
||||
if ($row->share) {
|
||||
return $row;
|
||||
if ($row->share > 0) {
|
||||
return true;
|
||||
}
|
||||
$pid = $row->pid;
|
||||
}
|
||||
@@ -165,60 +138,18 @@ class File extends AbstractModel
|
||||
* @param $share
|
||||
* @return bool
|
||||
*/
|
||||
public function updataShare($share = null)
|
||||
public function setShare($share)
|
||||
{
|
||||
if ($share === null) {
|
||||
$share = FileUser::whereFileId($this->id)->count() == 0 ? 0 : 1;
|
||||
}
|
||||
if ($this->share != $share) {
|
||||
AbstractModel::transaction(function () use ($share) {
|
||||
$this->share = $share;
|
||||
$this->save();
|
||||
if ($share === 0) {
|
||||
FileUser::deleteFileAll($this->id, $this->userid);
|
||||
AbstractModel::transaction(function () use ($share) {
|
||||
$this->share = $share;
|
||||
$this->save();
|
||||
$list = self::wherePid($this->id)->get();
|
||||
if ($list->isNotEmpty()) {
|
||||
foreach ($list as $item) {
|
||||
$item->setShare(0);
|
||||
}
|
||||
$list = self::wherePid($this->id)->get();
|
||||
if ($list->isNotEmpty()) {
|
||||
foreach ($list as $item) {
|
||||
$item->updataShare(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前更新pids
|
||||
* @return bool
|
||||
*/
|
||||
public function saveBeforePids()
|
||||
{
|
||||
$pid = $this->pid;
|
||||
$array = [];
|
||||
while ($pid > 0) {
|
||||
$array[] = $pid;
|
||||
$pid = intval(self::whereId($pid)->value('pid'));
|
||||
}
|
||||
$opids = $this->pids;
|
||||
if ($array) {
|
||||
$array = array_values(array_reverse($array));
|
||||
$this->pids = ',' . implode(',', $array) . ',';
|
||||
} else {
|
||||
$this->pids = '';
|
||||
}
|
||||
if (!$this->save()) {
|
||||
return false;
|
||||
}
|
||||
// 更新子文件(夹)
|
||||
if ($opids != $this->pids) {
|
||||
self::wherePid($this->id)->chunkById(100, function ($lists) {
|
||||
/** @var self $item */
|
||||
foreach ($lists as $item) {
|
||||
$item->saveBeforePids();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -231,7 +162,6 @@ class File extends AbstractModel
|
||||
AbstractModel::transaction(function () {
|
||||
$this->delete();
|
||||
$this->pushMsg('delete');
|
||||
FileUser::deleteFileAll($this->id);
|
||||
FileContent::whereFid($this->id)->delete();
|
||||
$list = self::wherePid($this->id)->get();
|
||||
if ($list->isNotEmpty()) {
|
||||
@@ -259,15 +189,15 @@ class File extends AbstractModel
|
||||
//
|
||||
if ($userid === null) {
|
||||
$userid = [$this->userid];
|
||||
$builder = WebSocket::select(['userid']);
|
||||
if ($action == 'content') {
|
||||
$builder->wherePath("/single/file/{$this->id}");
|
||||
} elseif ($this->pid > 0) {
|
||||
$builder->wherePath("/manage/file/{$this->pid}");
|
||||
} else {
|
||||
$builder->wherePath("/manage/file");
|
||||
if ($this->share == 1) {
|
||||
$builder = WebSocket::select(['userid']);
|
||||
if ($action == 'content') {
|
||||
$builder->wherePath('file/content/' . $this->id);
|
||||
}
|
||||
$userid = array_merge($userid, $builder->pluck('userid')->toArray());
|
||||
} elseif ($this->share == 2) {
|
||||
$userid = array_merge($userid, FileUser::whereFileId($this->id)->pluck('userid')->toArray());
|
||||
}
|
||||
$userid = array_merge($userid, $builder->pluck('userid')->toArray());
|
||||
$userid = array_values(array_filter(array_unique($userid)));
|
||||
}
|
||||
if (empty($userid)) {
|
||||
@@ -292,178 +222,19 @@ class File extends AbstractModel
|
||||
Task::deliver($task);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理返回图片地址
|
||||
* @param array $item
|
||||
* @return array
|
||||
*/
|
||||
public static function handleImageUrl($item)
|
||||
{
|
||||
if (in_array($item['ext'], self::imageExt) ) {
|
||||
$content = Base::json2array(FileContent::whereFid($item['id'])->orderByDesc('id')->value('content'));
|
||||
if ($content) {
|
||||
$item['image_url'] = Base::fillUrl($content['url']);
|
||||
}
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件并检测权限
|
||||
* @param $id
|
||||
* @param int $limit 要求权限: 0-访问权限、1-读写权限、1000-所有者或创建者
|
||||
* @param $permission
|
||||
* @param null $noExistTis
|
||||
* @return File
|
||||
*/
|
||||
public static function permissionFind($id, $limit = 0, &$permission = -1)
|
||||
public static function allowFind($id, $noExistTis = null)
|
||||
{
|
||||
$file = File::find($id);
|
||||
if (empty($file)) {
|
||||
throw new ApiException('文件不存在或已被删除');
|
||||
}
|
||||
//
|
||||
$permission = $file->getPermission(User::userid());
|
||||
if ($permission < $limit) {
|
||||
$msg = match ($limit) {
|
||||
1000 => '仅限所有者或创建者操作',
|
||||
1 => '没有修改写入权限',
|
||||
default => '没有查看访问权限',
|
||||
};
|
||||
throw new ApiException($msg);
|
||||
throw new ApiException($noExistTis ?: '文件不存在或已被删除');
|
||||
}
|
||||
$file->exceAllow(User::userid());
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化内容数据
|
||||
* @param array $data [path, size, ext, name]
|
||||
* @return array
|
||||
*/
|
||||
public static function formatFileData(array $data)
|
||||
{
|
||||
$filePath = $data['path'];
|
||||
$fileSize = $data['size'];
|
||||
$fileExt = $data['ext'];
|
||||
$publicPath = public_path($filePath);
|
||||
//
|
||||
switch ($fileExt) {
|
||||
case 'md':
|
||||
case 'text':
|
||||
// 文本
|
||||
$data['content'] = [
|
||||
'type' => $fileExt,
|
||||
'content' => file_get_contents($publicPath) ?: 'Content deleted',
|
||||
];
|
||||
$data['file_mode'] = $fileExt;
|
||||
break;
|
||||
|
||||
case 'drawio':
|
||||
// 图表
|
||||
$data['content'] = [
|
||||
'xml' => file_get_contents($publicPath)
|
||||
];
|
||||
$data['file_mode'] = $fileExt;
|
||||
break;
|
||||
|
||||
case 'mind':
|
||||
// 思维导图
|
||||
$data['content'] = Base::json2array(file_get_contents($publicPath));
|
||||
$data['file_mode'] = $fileExt;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (in_array($fileExt, self::codeExt) && $fileSize < 2 * 1024 * 1024)
|
||||
{
|
||||
// 文本预览,限制2M内的文件
|
||||
$data['content'] = [
|
||||
'content' => file_get_contents($publicPath) ?: 'Content deleted',
|
||||
];
|
||||
$data['file_mode'] = 'code';
|
||||
}
|
||||
elseif (in_array($fileExt, File::officeExt))
|
||||
{
|
||||
// office预览
|
||||
$data['content'] = json_decode('{}');
|
||||
$data['file_mode'] = 'office';
|
||||
}
|
||||
else
|
||||
{
|
||||
// 其他预览
|
||||
if (in_array($fileExt, File::localExt)) {
|
||||
$url = Base::fillUrl($filePath);
|
||||
} else {
|
||||
$url = 'http://' . env('APP_IPPR') . '.3/' . $filePath;
|
||||
}
|
||||
if ($fileExt != 'pdf') {
|
||||
$fileDotExt = ".{$fileExt}";
|
||||
$fileName = Base::rightDelete($data['name'], $fileDotExt) . $fileDotExt;
|
||||
$url = Base::urlAddparameter($url, [
|
||||
'fullfilename' => $fileName
|
||||
]);
|
||||
}
|
||||
$data['content'] = [
|
||||
'preview' => true,
|
||||
'url' => base64_encode($url),
|
||||
];
|
||||
$data['file_mode'] = 'preview';
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移交文件
|
||||
* @param $originalUserid
|
||||
* @param $newUserid
|
||||
* @return void
|
||||
*/
|
||||
public static function transfer($originalUserid, $newUserid)
|
||||
{
|
||||
if (!self::whereUserid($originalUserid)->exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建一个文件夹存放移交的文件
|
||||
$name = User::userid2nickname($originalUserid) ?: ('ID:' . $originalUserid);
|
||||
$file = File::createInstance([
|
||||
'pid' => 0,
|
||||
'name' => "【{$name}】移交的文件",
|
||||
'type' => "folder",
|
||||
'ext' => "",
|
||||
'userid' => $newUserid,
|
||||
'created_id' => 0,
|
||||
]);
|
||||
$file->saveBeforePids();
|
||||
|
||||
// 移交文件
|
||||
self::whereUserid($originalUserid)->chunkById(100, function($list) use ($file, $newUserid) {
|
||||
/** @var self $item */
|
||||
foreach ($list as $item) {
|
||||
if ($item->pid === 0) {
|
||||
$item->pid = $file->id;
|
||||
}
|
||||
$item->userid = $newUserid;
|
||||
$item->saveBeforePids();
|
||||
}
|
||||
});
|
||||
|
||||
// 移交文件权限
|
||||
FileUser::whereUserid($originalUserid)->chunkById(100, function ($list) use ($newUserid) {
|
||||
/** @var FileUser $item */
|
||||
foreach ($list as $item) {
|
||||
$row = FileUser::whereFileId($item->file_id)->whereUserid($newUserid)->first();
|
||||
if ($row) {
|
||||
// 已存在则删除原数据,判断改变已存在的数据
|
||||
$row->permission = max($row->permission, $item->permission);
|
||||
$row->save();
|
||||
$item->delete();
|
||||
} else {
|
||||
// 不存在则改变原数据
|
||||
$item->userid = $newUserid;
|
||||
$item->save();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Response;
|
||||
|
||||
/**
|
||||
* App\Models\FileContent
|
||||
* Class FileContent
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $fid 文件ID
|
||||
* @property string|null $content 内容
|
||||
@@ -41,53 +42,43 @@ class FileContent extends AbstractModel
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
* 获取格式内容(或下载)
|
||||
* @param File $file
|
||||
* 获取格式内容
|
||||
* @param $type
|
||||
* @param $content
|
||||
* @param $download
|
||||
* @return array|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
*/
|
||||
public static function formatContent($file, $content, $download = false)
|
||||
public static function formatContent($type, $content)
|
||||
{
|
||||
$name = $file->ext ? "{$file->name}.{$file->ext}" : null;
|
||||
$content = Base::json2array($content ?: []);
|
||||
if (in_array($file->type, ['word', 'excel', 'ppt'])) {
|
||||
$content = Base::json2array($content);
|
||||
if (in_array($type, ['word', 'excel', 'ppt'])) {
|
||||
if (empty($content)) {
|
||||
return Response::download(resource_path('assets/statics/office/empty.' . str_replace(['word', 'excel', 'ppt'], ['docx', 'xlsx', 'pptx'], $file->type)), $name);
|
||||
return Response::download(resource_path('assets/statics/office/empty.' . str_replace(['word', 'excel', 'ppt'], ['docx', 'xlsx', 'pptx'], $type)));
|
||||
}
|
||||
return Response::download(public_path($content['url']), $name);
|
||||
return Response::download(public_path($content['url']));
|
||||
}
|
||||
if (empty($content)) {
|
||||
$content = match ($file->type) {
|
||||
$content = match ($type) {
|
||||
'document' => [
|
||||
"type" => $file->ext,
|
||||
"type" => "md",
|
||||
"content" => "",
|
||||
],
|
||||
'sheet' => [
|
||||
[
|
||||
"name" => "Sheet1",
|
||||
"config" => json_decode('{}'),
|
||||
]
|
||||
],
|
||||
default => json_decode('{}'),
|
||||
};
|
||||
if ($download) {
|
||||
abort(403, "This file is empty.");
|
||||
}
|
||||
} else {
|
||||
$path = $content['url'];
|
||||
if ($file->ext) {
|
||||
$res = File::formatFileData([
|
||||
'path' => $path,
|
||||
'ext' => $file->ext,
|
||||
'size' => $file->size,
|
||||
'name' => $file->name,
|
||||
]);
|
||||
$content = $res['content'];
|
||||
} else {
|
||||
$content['preview'] = false;
|
||||
}
|
||||
if ($download) {
|
||||
$filePath = public_path($path);
|
||||
if (isset($filePath)) {
|
||||
return Response::download($filePath, $name);
|
||||
} else {
|
||||
abort(403, "This file not support download.");
|
||||
$content['preview'] = false;
|
||||
if ($content['ext'] && !in_array($content['ext'], ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'])) {
|
||||
$url = 'http://' . env('APP_IPPR') . '.3/' . $content['url'];
|
||||
if ($type == 'image') {
|
||||
$url = Base::fillUrl($content['url']);
|
||||
}
|
||||
$content['url'] = base64_encode($url);
|
||||
$content['preview'] = true;
|
||||
}
|
||||
}
|
||||
return Base::retSuccess('success', [ 'content' => $content ]);
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\FileLink
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $file_id 文件ID
|
||||
* @property int|null $num 累计访问
|
||||
* @property string|null $code 链接码
|
||||
* @property int|null $userid 会员ID
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\File|null $file
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink query()
|
||||
* @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)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink whereNum($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileLink whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class FileLink extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function file(): \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
{
|
||||
return $this->hasOne(File::class, 'id', 'file_id');
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,12 @@ namespace App\Models;
|
||||
|
||||
|
||||
/**
|
||||
* App\Models\FileUser
|
||||
* Class FileUser
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $file_id 项目ID
|
||||
* @property int|null $userid 成员ID
|
||||
* @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|FileUser newModelQuery()
|
||||
@@ -18,41 +18,10 @@ namespace App\Models;
|
||||
* @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)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileUser wherePermission($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileUser whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|FileUser whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class FileUser extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* 删除所有共享成员(同时删除成员分享的链接)
|
||||
* @param $file_id
|
||||
* @param int $retain_link_userid 保留指定会员的链接
|
||||
* @return mixed
|
||||
*/
|
||||
public static function deleteFileAll($file_id, $retain_link_userid = 0)
|
||||
{
|
||||
return AbstractModel::transaction(function() use ($retain_link_userid, $file_id) {
|
||||
if ($retain_link_userid > 0) {
|
||||
FileLink::whereFileId($file_id)->where('userid', '!=', $retain_link_userid)->delete();
|
||||
} else {
|
||||
FileLink::whereFileId($file_id)->delete();
|
||||
}
|
||||
FileUser::whereFileId($file_id)->delete();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除指定共享成员(同时删除成员分享的链接)
|
||||
* @param $file_id
|
||||
* @param $userid
|
||||
* @return mixed
|
||||
*/
|
||||
public static function deleteFileUser($file_id, $userid)
|
||||
{
|
||||
return AbstractModel::transaction(function() use ($userid, $file_id) {
|
||||
FileLink::whereFileId($file_id)->whereUserid($userid)->delete();
|
||||
return self::whereFileId($file_id)->whereUserid($userid)->delete();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,36 +3,40 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Module\Base;
|
||||
use App\Tasks\PushTask;
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Request;
|
||||
|
||||
/**
|
||||
* App\Models\Project
|
||||
* Class Project
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property string|null $name 名称
|
||||
* @property string|null $desc 描述、备注
|
||||
* @property int|null $userid 创建人
|
||||
* @property int|null $dialog_id 聊天会话ID
|
||||
* @property int|mixed $dialog_id 聊天会话ID
|
||||
* @property string|null $archived_at 归档时间
|
||||
* @property int|null $archived_userid 归档会员
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
* @property-read int $owner_userid
|
||||
* @property-read int $task_complete
|
||||
* @property-read int $task_my_complete
|
||||
* @property-read int $task_my_num
|
||||
* @property-read int $task_my_percent
|
||||
* @property-read int $task_num
|
||||
* @property-read int $task_percent
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectColumn[] $projectColumn
|
||||
* @property-read int|null $project_column_count
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectLog[] $projectLog
|
||||
* @property-read int|null $project_log_count
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectUser[] $projectUser
|
||||
* @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|Project authData($userid = null)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Project newQuery()
|
||||
* @method static \Illuminate\Database\Query\Builder|Project onlyTrashed()
|
||||
@@ -55,14 +59,99 @@ class Project extends AbstractModel
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $hidden = [
|
||||
'deleted_at',
|
||||
const projectSelect = [
|
||||
'projects.*',
|
||||
'project_users.owner',
|
||||
];
|
||||
|
||||
protected $appends = [
|
||||
'task_num',
|
||||
'task_complete',
|
||||
'task_percent',
|
||||
'task_my_num',
|
||||
'task_my_complete',
|
||||
'task_my_percent',
|
||||
'owner_userid',
|
||||
];
|
||||
|
||||
/**
|
||||
* 生成任务数据
|
||||
*/
|
||||
private function generateTaskData()
|
||||
{
|
||||
if (!isset($this->appendattrs['task_num'])) {
|
||||
$builder = ProjectTask::whereProjectId($this->id)->whereParentId(0)->whereNull('archived_at');
|
||||
$this->appendattrs['task_num'] = $builder->count();
|
||||
$this->appendattrs['task_complete'] = $builder->whereNotNull('complete_at')->count();
|
||||
$this->appendattrs['task_percent'] = $this->appendattrs['task_num'] ? intval($this->appendattrs['task_complete'] / $this->appendattrs['task_num'] * 100) : 0;
|
||||
//
|
||||
$builder = ProjectTask::whereProjectId($this->id)->whereParentId(0)->authData(User::userid())->whereNull('archived_at');
|
||||
$this->appendattrs['task_my_num'] = $builder->count();
|
||||
$this->appendattrs['task_my_complete'] = $builder->whereNotNull('complete_at')->count();
|
||||
$this->appendattrs['task_my_percent'] = $this->appendattrs['task_my_num'] ? intval($this->appendattrs['task_my_complete'] / $this->appendattrs['task_my_num'] * 100) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务数量
|
||||
* @return int
|
||||
*/
|
||||
public function getTaskNumAttribute()
|
||||
{
|
||||
$this->generateTaskData();
|
||||
return $this->appendattrs['task_num'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务完成数量
|
||||
* @return int
|
||||
*/
|
||||
public function getTaskCompleteAttribute()
|
||||
{
|
||||
$this->generateTaskData();
|
||||
return $this->appendattrs['task_complete'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务完成率
|
||||
* @return int
|
||||
*/
|
||||
public function getTaskPercentAttribute()
|
||||
{
|
||||
$this->generateTaskData();
|
||||
return $this->appendattrs['task_percent'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务数量(我的)
|
||||
* @return int
|
||||
*/
|
||||
public function getTaskMyNumAttribute()
|
||||
{
|
||||
$this->generateTaskData();
|
||||
return $this->appendattrs['task_my_num'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务完成数量(我的)
|
||||
* @return int
|
||||
*/
|
||||
public function getTaskMyCompleteAttribute()
|
||||
{
|
||||
$this->generateTaskData();
|
||||
return $this->appendattrs['task_my_complete'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务完成率(我的)
|
||||
* @return int
|
||||
*/
|
||||
public function getTaskMyPercentAttribute()
|
||||
{
|
||||
$this->generateTaskData();
|
||||
return $this->appendattrs['task_my_percent'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 负责人会员ID
|
||||
* @return int
|
||||
@@ -70,7 +159,7 @@ class Project extends AbstractModel
|
||||
public function getOwnerUseridAttribute()
|
||||
{
|
||||
if (!isset($this->appendattrs['owner_userid'])) {
|
||||
$ownerUser = ProjectUser::whereProjectId($this->id)->whereOwner(1)->first();
|
||||
$ownerUser = $this->projectUser->where('owner', 1)->first();
|
||||
$this->appendattrs['owner_userid'] = $ownerUser ? $ownerUser->userid : 0;
|
||||
}
|
||||
return $this->appendattrs['owner_userid'];
|
||||
@@ -101,73 +190,19 @@ class Project extends AbstractModel
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有项目(与正常查询多返回owner字段)
|
||||
* 查询自己的项目
|
||||
* @param self $query
|
||||
* @param null $userid
|
||||
* @return self
|
||||
*/
|
||||
public function scopeAllData($query, $userid = null)
|
||||
public function scopeAuthData($query, $userid = null)
|
||||
{
|
||||
$userid = $userid ?: User::userid();
|
||||
$query
|
||||
->select([
|
||||
'projects.*',
|
||||
'project_users.owner',
|
||||
'project_users.top_at',
|
||||
])
|
||||
->leftJoin('project_users', function ($leftJoin) use ($userid) {
|
||||
$leftJoin
|
||||
->on('project_users.userid', '=', DB::raw($userid))
|
||||
->on('projects.id', '=', 'project_users.project_id');
|
||||
});
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询自己负责或参与的项目
|
||||
* @param self $query
|
||||
* @param null $userid
|
||||
* @param null $owner
|
||||
* @return self
|
||||
*/
|
||||
public function scopeAuthData($query, $userid = null, $owner = null)
|
||||
{
|
||||
$userid = $userid ?: User::userid();
|
||||
$query
|
||||
->select([
|
||||
'projects.*',
|
||||
'project_users.owner',
|
||||
'project_users.top_at',
|
||||
])
|
||||
->join('project_users', 'projects.id', '=', 'project_users.project_id')
|
||||
$query->join('project_users', 'projects.id', '=', 'project_users.project_id')
|
||||
->where('project_users.userid', $userid);
|
||||
if ($owner !== null) {
|
||||
$query->where('project_users.owner', $owner);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务统计数据
|
||||
* @param $userid
|
||||
* @return array
|
||||
*/
|
||||
public function getTaskStatistics($userid)
|
||||
{
|
||||
$array = [];
|
||||
$builder = ProjectTask::whereProjectId($this->id)->whereNull('archived_at');
|
||||
$array['task_num'] = $builder->count();
|
||||
$array['task_complete'] = $builder->whereNotNull('complete_at')->count();
|
||||
$array['task_percent'] = $array['task_num'] ? intval($array['task_complete'] / $array['task_num'] * 100) : 0;
|
||||
//
|
||||
$builder = ProjectTask::authData($userid, 1)->where('project_tasks.project_id', $this->id)->whereNull('project_tasks.archived_at');
|
||||
$array['task_my_num'] = $builder->count();
|
||||
$array['task_my_complete'] = $builder->whereNotNull('project_tasks.complete_at')->count();
|
||||
$array['task_my_percent'] = $array['task_my_num'] ? intval($array['task_my_complete'] / $array['task_my_num'] * 100) : 0;
|
||||
//
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入项目
|
||||
* @param int $userid 加入的会员ID
|
||||
@@ -214,7 +249,7 @@ class Project extends AbstractModel
|
||||
*/
|
||||
public function relationUserids()
|
||||
{
|
||||
return ProjectUser::whereProjectId($this->id)->orderBy('id')->pluck('userid')->toArray();
|
||||
return $this->projectUser->pluck('userid')->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,7 +277,6 @@ class Project extends AbstractModel
|
||||
if ($archived_at === null) {
|
||||
// 取消归档
|
||||
$this->archived_at = null;
|
||||
$this->archived_userid = User::userid();
|
||||
$this->addLog("项目取消归档");
|
||||
$this->pushMsg('add', $this);
|
||||
ProjectTask::whereProjectId($this->id)->whereArchivedFollow(1)->update([
|
||||
@@ -288,23 +322,18 @@ class Project extends AbstractModel
|
||||
/**
|
||||
* 添加项目日志
|
||||
* @param string $detail
|
||||
* @param array $record
|
||||
* @param int $userid
|
||||
* @return ProjectLog
|
||||
*/
|
||||
public function addLog($detail, $record = [], $userid = 0)
|
||||
public function addLog($detail, $userid = 0)
|
||||
{
|
||||
$array = [
|
||||
$log = ProjectLog::createInstance([
|
||||
'project_id' => $this->id,
|
||||
'column_id' => 0,
|
||||
'task_id' => 0,
|
||||
'userid' => $userid ?: User::userid(),
|
||||
'detail' => $detail,
|
||||
];
|
||||
if ($record) {
|
||||
$array['record'] = $record;
|
||||
}
|
||||
$log = ProjectLog::createInstance($array);
|
||||
]);
|
||||
$log->save();
|
||||
return $log;
|
||||
}
|
||||
@@ -312,180 +341,45 @@ class Project extends AbstractModel
|
||||
/**
|
||||
* 推送消息
|
||||
* @param string $action
|
||||
* @param array|self $data 发送内容,默认为[id=>项目ID]
|
||||
* @param array $userid 指定会员,默认为项目所有成员
|
||||
* @param array $data 发送内容,默认为[id=>项目ID]
|
||||
* @param array $userid 指定会员,默认为项目所有成员
|
||||
*/
|
||||
public function pushMsg($action, $data = null, $userid = null)
|
||||
{
|
||||
if ($data === null) {
|
||||
$data = ['id' => $this->id];
|
||||
} elseif ($data instanceof self) {
|
||||
$data = $data->toArray();
|
||||
}
|
||||
//
|
||||
$array = [$userid, []];
|
||||
if ($userid === null) {
|
||||
$array[0] = $this->relationUserids();
|
||||
} elseif (!is_array($userid)) {
|
||||
$array[0] = [$userid];
|
||||
}
|
||||
//
|
||||
if (isset($data['owner'])) {
|
||||
$owners = ProjectUser::whereProjectId($data['id'])->whereOwner(1)->pluck('userid')->toArray();
|
||||
$array = [array_intersect($array[0], $owners), array_diff($array[0], $owners)];
|
||||
}
|
||||
//
|
||||
foreach ($array as $index => $item) {
|
||||
if ($index > 0) {
|
||||
$data['owner'] = 0;
|
||||
}
|
||||
$params = [
|
||||
'ignoreFd' => Request::header('fd'),
|
||||
'userid' => array_values($item),
|
||||
'msg' => [
|
||||
'type' => 'project',
|
||||
'action' => $action,
|
||||
'data' => $data,
|
||||
]
|
||||
];
|
||||
$task = new PushTask($params, false);
|
||||
Task::deliver($task);
|
||||
$userid = $this->relationUserids();
|
||||
}
|
||||
$params = [
|
||||
'ignoreFd' => Request::header('fd'),
|
||||
'userid' => $userid,
|
||||
'msg' => [
|
||||
'type' => 'project',
|
||||
'action' => $action,
|
||||
'data' => $data,
|
||||
]
|
||||
];
|
||||
$task = new PushTask($params, false);
|
||||
Task::deliver($task);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加工作流
|
||||
* @param $flows
|
||||
* @return mixed
|
||||
*/
|
||||
public function addFlow($flows)
|
||||
{
|
||||
return AbstractModel::transaction(function() use ($flows) {
|
||||
$projectFlow = ProjectFlow::whereProjectId($this->id)->first();
|
||||
if (empty($projectFlow)) {
|
||||
$projectFlow = ProjectFlow::createInstance([
|
||||
'project_id' => $this->id,
|
||||
'name' => 'Default'
|
||||
]);
|
||||
if (!$projectFlow->save()) {
|
||||
throw new ApiException('工作流创建失败');
|
||||
}
|
||||
}
|
||||
//
|
||||
$ids = [];
|
||||
$idc = [];
|
||||
$hasStart = false;
|
||||
$hasEnd = false;
|
||||
$upTaskList = [];
|
||||
foreach ($flows as $item) {
|
||||
$id = intval($item['id']);
|
||||
$turns = Base::arrayRetainInt($item['turns'] ?: [], true);
|
||||
$userids = Base::arrayRetainInt($item['userids'] ?: [], true);
|
||||
$usertype = trim($item['usertype']);
|
||||
$userlimit = intval($item['userlimit']);
|
||||
if ($usertype == 'replace' && empty($userids)) {
|
||||
throw new ApiException("状态[{$item['name']}]设置错误,设置流转模式时必须填写状态负责人");
|
||||
}
|
||||
if ($usertype == 'merge' && empty($userids)) {
|
||||
throw new ApiException("状态[{$item['name']}]设置错误,设置剔除模式时必须填写状态负责人");
|
||||
}
|
||||
if ($userlimit && empty($userids)) {
|
||||
throw new ApiException("状态[{$item['name']}]设置错误,设置限制负责人时必须填写状态负责人");
|
||||
}
|
||||
$flow = ProjectFlowItem::updateInsert([
|
||||
'id' => $id,
|
||||
'project_id' => $this->id,
|
||||
'flow_id' => $projectFlow->id,
|
||||
], [
|
||||
'name' => trim($item['name']),
|
||||
'status' => trim($item['status']),
|
||||
'sort' => intval($item['sort']),
|
||||
'turns' => $turns,
|
||||
'userids' => $userids,
|
||||
'usertype' => trim($item['usertype']),
|
||||
'userlimit' => $userlimit,
|
||||
], [], $isInsert);
|
||||
if ($flow) {
|
||||
$ids[] = $flow->id;
|
||||
if ($flow->id != $id) {
|
||||
$idc[$id] = $flow->id;
|
||||
}
|
||||
if ($flow->status == 'start') {
|
||||
$hasStart = true;
|
||||
}
|
||||
if ($flow->status == 'end') {
|
||||
$hasEnd = true;
|
||||
}
|
||||
if (!$isInsert) {
|
||||
$upTaskList[$flow->id] = $flow->status . "|" . $flow->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$hasStart) {
|
||||
throw new ApiException('至少需要1个开始状态');
|
||||
}
|
||||
if (!$hasEnd) {
|
||||
throw new ApiException('至少需要1个结束状态');
|
||||
}
|
||||
ProjectFlowItem::whereFlowId($projectFlow->id)->whereNotIn('id', $ids)->chunk(100, function($list) {
|
||||
foreach ($list as $item) {
|
||||
$item->deleteFlowItem();
|
||||
}
|
||||
});
|
||||
//
|
||||
foreach ($upTaskList as $id => $value) {
|
||||
ProjectTask::whereFlowItemId($id)->update([
|
||||
'flow_item_name' => $value
|
||||
]);
|
||||
}
|
||||
//
|
||||
$projectFlow = ProjectFlow::with(['projectFlowItem'])->whereProjectId($this->id)->find($projectFlow->id);
|
||||
$itemIds = $projectFlow->projectFlowItem->pluck('id')->toArray();
|
||||
foreach ($projectFlow->projectFlowItem as $item) {
|
||||
$turns = $item->turns;
|
||||
foreach ($idc as $oid => $nid) {
|
||||
if (in_array($oid, $turns)) {
|
||||
$turns = array_diff($turns, [$oid]);
|
||||
$turns[] = $nid;
|
||||
}
|
||||
}
|
||||
if (!in_array($item->id, $turns)) {
|
||||
$turns[] = $item->id;
|
||||
}
|
||||
$turns = array_values(array_filter(array_unique(array_intersect($turns, $itemIds))));
|
||||
sort($turns);
|
||||
$item->turns = $turns;
|
||||
ProjectFlowItem::whereId($item->id)->update([ 'turns' => Base::array2json($turns) ]);
|
||||
}
|
||||
return $projectFlow;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目信息(用于判断会员是否存在项目内)
|
||||
* 根据用户获取项目信息(用于判断会员是否存在项目内)
|
||||
* @param int $project_id
|
||||
* @param null|bool $archived true:仅限未归档, false:仅限已归档, null:不限制
|
||||
* @param null|bool $mustOwner true:仅限项目负责人, false:仅限非项目负责人, null:不限制
|
||||
* @param bool $ignoreArchived 排除已归档
|
||||
* @return self
|
||||
*/
|
||||
public static function userProject($project_id, $archived = true, $mustOwner = null)
|
||||
public static function userProject($project_id, $ignoreArchived = true)
|
||||
{
|
||||
$project = self::authData()->where('projects.id', intval($project_id))->first();
|
||||
$project = self::select(self::projectSelect)->authData()->where('projects.id', intval($project_id))->first();
|
||||
if (empty($project)) {
|
||||
throw new ApiException('项目不存在或不在成员列表内', [ 'project_id' => $project_id ], -4001);
|
||||
}
|
||||
if ($archived === true && $project->archived_at != null) {
|
||||
if ($ignoreArchived && $project->archived_at != null) {
|
||||
throw new ApiException('项目已归档', [ 'project_id' => $project_id ], -4001);
|
||||
}
|
||||
if ($archived === false && $project->archived_at == null) {
|
||||
throw new ApiException('项目未归档', [ 'project_id' => $project_id ]);
|
||||
}
|
||||
if ($mustOwner === true && !$project->owner) {
|
||||
throw new ApiException('仅限项目负责人操作', [ 'project_id' => $project_id ]);
|
||||
}
|
||||
if ($mustOwner === false && $project->owner) {
|
||||
throw new ApiException('禁止项目负责人操作', [ 'project_id' => $project_id ]);
|
||||
}
|
||||
return $project;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Request;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectColumn
|
||||
* Class ProjectColumn
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property string|null $name 列表名称
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Module\Base;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectFlow
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property string|null $name 流程名称
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProjectFlowItem[] $projectFlowItem
|
||||
* @property-read int|null $project_flow_item_count
|
||||
* @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|ProjectFlow whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlow whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlow whereName($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlow whereProjectId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlow whereUpdatedAt($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ProjectFlow extends AbstractModel
|
||||
{
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function projectFlowItem(): \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
{
|
||||
return $this->hasMany(ProjectFlowItem::class, 'flow_id', 'id')->orderBy('sort');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function deleteFlow()
|
||||
{
|
||||
return AbstractModel::transaction(function() {
|
||||
ProjectFlowItem::whereProjectId($this->project_id)->chunk(100, function($list) {
|
||||
foreach ($list as $item) {
|
||||
$item->deleteFlowItem();
|
||||
}
|
||||
});
|
||||
return $this->delete();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Module\Base;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectFlowItem
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property int|null $flow_id 流程ID
|
||||
* @property string|null $name 名称
|
||||
* @property string|null $status 状态
|
||||
* @property array $turns 可流转
|
||||
* @property array $userids 状态负责人ID
|
||||
* @property string|null $usertype 流转模式
|
||||
* @property int|null $userlimit 限制负责人
|
||||
* @property int|null $sort 排序
|
||||
* @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|ProjectFlowItem newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereFlowId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereName($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereProjectId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereSort($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereStatus($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereTurns($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereUserids($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereUserlimit($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectFlowItem whereUsertype($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ProjectFlowItem extends AbstractModel
|
||||
{
|
||||
protected $hidden = [
|
||||
'created_at',
|
||||
'updated_at',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return array
|
||||
*/
|
||||
public function getTurnsAttribute($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
return Base::json2array($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return array
|
||||
*/
|
||||
public function getUseridsAttribute($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
return Base::json2array($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function projectFlow(): \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
{
|
||||
return $this->hasOne(ProjectFlow::class, 'id', 'flow_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|null
|
||||
*/
|
||||
public function deleteFlowItem()
|
||||
{
|
||||
ProjectTask::whereFlowItemId($this->id)->update([
|
||||
'flow_item_id' => 0,
|
||||
'flow_item_name' => "",
|
||||
]);
|
||||
return $this->delete();
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectInvite
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property int|null $num 累计邀请
|
||||
* @property string|null $code 链接码
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read bool $already
|
||||
* @property-read \App\Models\Project|null $project
|
||||
* @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|ProjectInvite whereCode($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite whereNum($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite whereProjectId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectInvite whereUpdatedAt($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ProjectInvite extends AbstractModel
|
||||
{
|
||||
protected $appends = [
|
||||
'already',
|
||||
];
|
||||
|
||||
/**
|
||||
* 是否已加入
|
||||
* @return bool
|
||||
*/
|
||||
public function getAlreadyAttribute()
|
||||
{
|
||||
if (!isset($this->appendattrs['already'])) {
|
||||
$this->appendattrs['already'] = false;
|
||||
if (User::userid()) {
|
||||
$this->appendattrs['already'] = (bool)$this->project?->projectUser?->where('userid', User::userid())->count();
|
||||
}
|
||||
}
|
||||
return $this->appendattrs['already'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function project(): \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
{
|
||||
return $this->hasOne(Project::class, 'id', 'project_id');
|
||||
}
|
||||
}
|
||||
@@ -2,21 +2,18 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Module\Base;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectLog
|
||||
* Class ProjectLog
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property int|null $column_id 列表ID
|
||||
* @property int|null $task_id 任务ID
|
||||
* @property int|null $task_id 项目ID
|
||||
* @property int|null $userid 会员ID
|
||||
* @property string|null $detail 详细信息
|
||||
* @property array $record 记录数据
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @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|ProjectLog newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog newQuery()
|
||||
@@ -26,7 +23,6 @@ use App\Module\Base;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereDetail($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereProjectId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereRecord($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereTaskId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectLog whereUserid($value)
|
||||
@@ -35,18 +31,6 @@ use App\Module\Base;
|
||||
class ProjectLog extends AbstractModel
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @return array
|
||||
*/
|
||||
public function getRecordAttribute($value)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
return Base::json2array($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
@@ -55,12 +39,4 @@ class ProjectLog extends AbstractModel
|
||||
return $this->hasOne(User::class, 'userid', 'userid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function projectTask(): \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
{
|
||||
return $this->hasOne(ProjectTask::class, 'id', 'task_id');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,11 +2,10 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Module\Base;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectTaskContent
|
||||
* Class ProjectTaskContent
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property int|null $task_id 任务ID
|
||||
@@ -30,54 +29,4 @@ class ProjectTaskContent extends AbstractModel
|
||||
'created_at',
|
||||
'updated_at',
|
||||
];
|
||||
|
||||
/**
|
||||
* 获取内容详情
|
||||
* @return array
|
||||
*/
|
||||
public function getContentInfo()
|
||||
{
|
||||
$content = Base::json2array($this->content);
|
||||
if (isset($content['url'])) {
|
||||
$filePath = public_path($content['url']);
|
||||
$array = $this->toArray();
|
||||
$array['content'] = file_get_contents($filePath) ?: '';
|
||||
if ($array['content']) {
|
||||
$replace = Base::fillUrl('uploads/task');
|
||||
$array['content'] = str_replace('{{RemoteURL}}uploads/task', $replace, $array['content']);
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
return $this->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存任务详情至文件并返回文件路径
|
||||
* @param $task_id
|
||||
* @param $content
|
||||
* @return string
|
||||
*/
|
||||
public static function saveContent($task_id, $content)
|
||||
{
|
||||
$path = 'uploads/task/content/' . date("Ym") . '/' . $task_id . '/';
|
||||
//
|
||||
preg_match_all("/<img\s*src=\"data:image\/(png|jpg|jpeg);base64,(.*?)\"/s", $content, $matchs);
|
||||
foreach ($matchs[2] as $key => $text) {
|
||||
$tmpPath = $path . 'attached/';
|
||||
Base::makeDir(public_path($tmpPath));
|
||||
$tmpPath .= md5($text) . "." . $matchs[1][$key];
|
||||
if (file_put_contents(public_path($tmpPath), base64_decode($text))) {
|
||||
$content = str_replace($matchs[0][$key], '<img src="{{RemoteURL}}' . $tmpPath . '"', $content);
|
||||
}
|
||||
}
|
||||
$pattern = '/<img(.*?)src=("|\')https*:\/\/(.*?)\/(uploads\/task\/content\/(.*?))\2/is';
|
||||
$content = preg_replace($pattern, '<img$1src=$2{{RemoteURL}}$4$2', $content);
|
||||
//
|
||||
$filePath = $path . md5($content);
|
||||
$publicPath = public_path($filePath);
|
||||
Base::makeDir(dirname($publicPath));
|
||||
file_put_contents($publicPath, $content);
|
||||
//
|
||||
return $filePath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,16 +5,17 @@ namespace App\Models;
|
||||
use App\Module\Base;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectTaskFile
|
||||
* Class ProjectTaskFile
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property int|null $task_id 任务ID
|
||||
* @property string|null $name 文件名称
|
||||
* @property int|null $size 文件大小(B)
|
||||
* @property string|null $ext 文件格式
|
||||
* @property string $path 文件地址
|
||||
* @property string $thumb 缩略图
|
||||
* @property string|null $path 文件地址
|
||||
* @property string|null $thumb 缩略图
|
||||
* @property int|null $userid 上传用户ID
|
||||
* @property int|null $download 下载次数
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectTaskFlowChange
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $task_id 任务ID
|
||||
* @property int|null $userid 会员ID
|
||||
* @property int|null $before_flow_item_id (变化前)工作流状态ID
|
||||
* @property string|null $before_flow_item_name (变化前)工作流状态名称
|
||||
* @property int|null $after_flow_item_id (变化后)工作流状态ID
|
||||
* @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|ProjectTaskFlowChange newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange query()
|
||||
* @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)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereBeforeFlowItemName($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereTaskId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskFlowChange whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ProjectTaskFlowChange extends AbstractModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
|
||||
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectTaskMailLog
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $userid 用户id
|
||||
* @property int|null $task_id 任务id
|
||||
* @property string|null $email 电子邮箱
|
||||
* @property int|null $type 提醒类型:1第一次任务提醒,2第二次任务超期提醒
|
||||
* @property int|null $is_send 邮件发送是否成功:0否,1是
|
||||
* @property string|null $send_error 邮件发送错误详情
|
||||
* @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|ProjectTaskMailLog newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog newQuery()
|
||||
* @method static \Illuminate\Database\Query\Builder|ProjectTaskMailLog onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog whereDeletedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog whereEmail($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog whereIsSend($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog whereSendError($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog whereTaskId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog whereType($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskMailLog whereUserid($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|ProjectTaskMailLog withTrashed()
|
||||
* @method static \Illuminate\Database\Query\Builder|ProjectTaskMailLog withoutTrashed()
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ProjectTaskMailLog extends AbstractModel
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
}
|
||||
@@ -3,8 +3,9 @@
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectTaskTag
|
||||
* Class ProjectTaskTag
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property int|null $task_id 任务ID
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectTaskUser
|
||||
* Class ProjectTaskUser
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property int|null $task_id 任务ID
|
||||
@@ -13,7 +14,6 @@ namespace App\Models;
|
||||
* @property int|null $owner 是否任务负责人
|
||||
* @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|ProjectTaskUser newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectTaskUser query()
|
||||
@@ -30,45 +30,4 @@ namespace App\Models;
|
||||
class ProjectTaskUser extends AbstractModel
|
||||
{
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function projectTask(): \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
{
|
||||
return $this->hasOne(ProjectTask::class, 'id', 'task_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 移交任务身份
|
||||
* @param $originalUserid
|
||||
* @param $newUserid
|
||||
* @return void
|
||||
*/
|
||||
public static function transfer($originalUserid, $newUserid)
|
||||
{
|
||||
self::whereUserid($originalUserid)->chunk(100, function ($list) use ($newUserid) {
|
||||
$tastIds = [];
|
||||
/** @var self $item */
|
||||
foreach ($list as $item) {
|
||||
$row = self::whereTaskId($item->task_id)->whereUserid($newUserid)->first();
|
||||
if ($row) {
|
||||
// 已存在则删除原数据,判断改变已存在的数据
|
||||
$row->owner = max($row->owner, $item->owner);
|
||||
$row->save();
|
||||
$item->delete();
|
||||
} else {
|
||||
// 不存在则改变原数据
|
||||
$item->userid = $newUserid;
|
||||
$item->save();
|
||||
}
|
||||
if ($item->projectTask) {
|
||||
$item->projectTask->addLog("移交{任务}身份给", ['userid' => [$newUserid]]);
|
||||
if (!in_array($item->task_pid, $tastIds)) {
|
||||
$tastIds[] = $item->task_pid;
|
||||
$item->projectTask->syncDialogUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@ namespace App\Models;
|
||||
use App\Module\Base;
|
||||
|
||||
/**
|
||||
* App\Models\ProjectUser
|
||||
* Class ProjectUser
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $project_id 项目ID
|
||||
* @property int|null $userid 成员ID
|
||||
* @property int|null $owner 是否负责人
|
||||
* @property string|null $top_at 置顶时间
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property-read \App\Models\Project|null $project
|
||||
@@ -22,7 +22,6 @@ use App\Module\Base;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereOwner($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereProjectId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereTopAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ProjectUser whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
@@ -38,54 +37,17 @@ class ProjectUser extends AbstractModel
|
||||
return $this->hasOne(Project::class, 'id', 'project_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 移交项目身份
|
||||
* @param $originalUserid
|
||||
* @param $newUserid
|
||||
* @return void
|
||||
*/
|
||||
public static function transfer($originalUserid, $newUserid)
|
||||
{
|
||||
self::whereUserid($originalUserid)->chunkById(100, function ($list) use ($newUserid) {
|
||||
/** @var self $item */
|
||||
foreach ($list as $item) {
|
||||
$row = self::whereProjectId($item->project_id)->whereUserid($newUserid)->first();
|
||||
if ($row) {
|
||||
// 已存在则删除原数据,判断改变已存在的数据
|
||||
$row->owner = max($row->owner, $item->owner);
|
||||
$row->save();
|
||||
$item->delete();
|
||||
} else {
|
||||
// 不存在则改变原数据
|
||||
$item->userid = $newUserid;
|
||||
$item->save();
|
||||
}
|
||||
if ($item->project) {
|
||||
$item->project->addLog("移交项目身份给", ['userid' => $newUserid]);
|
||||
$item->project->syncDialogUser();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出项目
|
||||
*/
|
||||
public function exitProject()
|
||||
{
|
||||
ProjectTaskUser::whereProjectId($this->project_id)
|
||||
->whereUserid($this->userid)
|
||||
->chunk(100, function ($list) {
|
||||
$tastIds = [];
|
||||
/** @var ProjectTaskUser $item */
|
||||
foreach ($list as $item) {
|
||||
$item->delete();
|
||||
if (!in_array($item->task_pid, $tastIds)) {
|
||||
$tastIds[] = $item->task_pid;
|
||||
$item->projectTask?->syncDialogUser();
|
||||
}
|
||||
}
|
||||
});
|
||||
$tasks = ProjectTask::whereProjectId($this->project_id)->authData($this->userid)->get();
|
||||
foreach ($tasks as $task) {
|
||||
if (ProjectTaskUser::whereTaskId($task->id)->whereUserid($this->userid)->delete()) {
|
||||
$task->syncDialogUser();
|
||||
}
|
||||
}
|
||||
$this->delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use Carbon\Carbon;
|
||||
use Carbon\Traits\Creator;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
|
||||
/**
|
||||
* App\Models\Report
|
||||
*
|
||||
* @property int $id
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property string $title 标题
|
||||
* @property string $type 汇报类型
|
||||
* @property int $userid
|
||||
* @property string $content
|
||||
* @property string $sign 汇报唯一标识
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ReportReceive[] $Receives
|
||||
* @property-read int|null $receives_count
|
||||
* @property-read mixed $receives
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\User[] $receivesUser
|
||||
* @property-read int|null $receives_user_count
|
||||
* @property-read \App\Models\User|null $sendUser
|
||||
* @method static Builder|Report newModelQuery()
|
||||
* @method static Builder|Report newQuery()
|
||||
* @method static Builder|Report query()
|
||||
* @method static Builder|Report whereContent($value)
|
||||
* @method static Builder|Report whereCreatedAt($value)
|
||||
* @method static Builder|Report whereId($value)
|
||||
* @method static Builder|Report whereSign($value)
|
||||
* @method static Builder|Report whereTitle($value)
|
||||
* @method static Builder|Report whereType($value)
|
||||
* @method static Builder|Report whereUpdatedAt($value)
|
||||
* @method static Builder|Report whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class Report extends AbstractModel
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
const WEEKLY = "weekly";
|
||||
const DAILY = "daily";
|
||||
|
||||
protected $fillable = [
|
||||
"title",
|
||||
"type",
|
||||
"userid",
|
||||
"content",
|
||||
];
|
||||
|
||||
protected $appends = [
|
||||
'receives',
|
||||
];
|
||||
|
||||
public function Receives(): HasMany
|
||||
{
|
||||
return $this->hasMany(ReportReceive::class, "rid");
|
||||
}
|
||||
|
||||
public function receivesUser(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(User::class, ReportReceive::class, "rid", "userid")
|
||||
->withPivot("receive_time", "read");
|
||||
}
|
||||
|
||||
public function sendUser()
|
||||
{
|
||||
return $this->hasOne(User::class, "userid", "userid");
|
||||
}
|
||||
|
||||
public function getTypeAttribute($value): string
|
||||
{
|
||||
return match ($value) {
|
||||
Report::WEEKLY => "周报",
|
||||
Report::DAILY => "日报",
|
||||
default => "",
|
||||
};
|
||||
}
|
||||
|
||||
public function getContentAttribute($value): string
|
||||
{
|
||||
return htmlspecialchars_decode($value);
|
||||
}
|
||||
|
||||
public function getReceivesAttribute()
|
||||
{
|
||||
if (!isset($this->appendattrs['receives'])) {
|
||||
$this->appendattrs['receives'] = empty( $this->receivesUser ) ? [] : array_column($this->receivesUser->toArray(), "userid");
|
||||
}
|
||||
return $this->appendattrs['receives'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单条记录
|
||||
* @param $id
|
||||
* @return Report|Builder|Model|object|null
|
||||
* @throw ApiException
|
||||
*/
|
||||
public static function getOne($id)
|
||||
{
|
||||
$one = self::whereId($id)->first();
|
||||
if (empty($one))
|
||||
throw new ApiException("记录不存在");
|
||||
return $one;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后一条提交记录
|
||||
* @param User|null $user
|
||||
* @return Builder|Model|\Illuminate\Database\Query\Builder|object
|
||||
*/
|
||||
public static function getLastOne(User $user = null)
|
||||
{
|
||||
$user === null && $user = User::auth();
|
||||
$one = self::whereUserid($user->userid)->orderByDesc("created_at")->first();
|
||||
if ( empty($one) )
|
||||
throw new ApiException("记录不存在");
|
||||
return $one;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一标识
|
||||
* @param $type
|
||||
* @param $offset
|
||||
* @param Carbon|null $time
|
||||
* @return string
|
||||
*/
|
||||
public static function generateSign($type, $offset, Carbon $time = null): string
|
||||
{
|
||||
$user = User::auth();
|
||||
$now_dt = $time === null ? Carbon::now() : $time;
|
||||
$time_s = match ($type) {
|
||||
Report::WEEKLY => function() use ($now_dt, $offset) {
|
||||
// 如果设置了周期偏移量
|
||||
empty( $offset ) || $now_dt->subWeeks( abs( $offset ) );
|
||||
$now_dt->startOfWeek(); // 设置为当周第一天
|
||||
return $now_dt->year . $now_dt->weekOfYear;
|
||||
},
|
||||
Report::DAILY => function() use ($now_dt, $offset) {
|
||||
// 如果设置了周期偏移量
|
||||
empty( $offset ) || $now_dt->subDays( abs( $offset ) );
|
||||
return $now_dt->format("Ymd");
|
||||
},
|
||||
default => "",
|
||||
};
|
||||
return $user->userid . ( is_callable($time_s) ? $time_s() : "" );
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* App\Models\ReportReceive
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $rid
|
||||
* @property string|null $receive_time 接收时间
|
||||
* @property int $userid 接收人
|
||||
* @property int $read 是否已读
|
||||
* @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|ReportReceive whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereRead($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereReceiveTime($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereRid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|ReportReceive whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class ReportReceive extends AbstractModel
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
// 关闭时间戳自动写入
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [
|
||||
"rid",
|
||||
"receive_time",
|
||||
"userid",
|
||||
"read",
|
||||
];
|
||||
}
|
||||
@@ -3,8 +3,9 @@
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\Setting
|
||||
* Class Setting
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property string|null $name
|
||||
* @property string|null $desc 参数描述、备注
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\Tmp
|
||||
* Class Tmp
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property string|null $name
|
||||
* @property string|null $value
|
||||
|
||||
@@ -9,8 +9,9 @@ use Cache;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* App\Models\User
|
||||
* Class User
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $userid
|
||||
* @property array $identity 身份
|
||||
* @property string|null $az A-Z
|
||||
@@ -28,11 +29,8 @@ use Carbon\Carbon;
|
||||
* @property string|null $line_at 最后在线时间(接口)
|
||||
* @property int|null $task_dialog_id 最后打开的任务会话ID
|
||||
* @property string|null $created_ip 注册IP
|
||||
* @property string|null $disable_at 禁用时间(离职时间)
|
||||
* @property int|null $email_verity 邮箱是否已验证
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Database\Factories\UserFactory factory(...$parameters)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User query()
|
||||
@@ -40,9 +38,7 @@ use Carbon\Carbon;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereChangepass($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereCreatedIp($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereDisableAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereEmail($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereEmailVerity($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereEncrypt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereIdentity($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|User whereLastAt($value)
|
||||
@@ -168,16 +164,6 @@ class User extends AbstractModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除会员
|
||||
* @return bool|null
|
||||
*/
|
||||
public function deleteUser()
|
||||
{
|
||||
UserEmailVerification::whereEmail($this->email)->delete();
|
||||
return $this->delete();
|
||||
}
|
||||
|
||||
/** ***************************************************************************************** */
|
||||
/** ***************************************************************************************** */
|
||||
/** ***************************************************************************************** */
|
||||
@@ -192,16 +178,10 @@ class User extends AbstractModel
|
||||
public static function reg($email, $password, $other = [])
|
||||
{
|
||||
//邮箱
|
||||
if (!Base::isEmail($email)) {
|
||||
if (!Base::isMail($email)) {
|
||||
throw new ApiException('请输入正确的邮箱地址');
|
||||
}
|
||||
if (User::email2userid($email) > 0) {
|
||||
$isRegVerify = Base::settingFind('emailSetting', 'reg_verify') === 'open';
|
||||
$user = self::whereUserid(User::email2userid($email))->first();
|
||||
if ($isRegVerify && $user->email_verity === 0) {
|
||||
UserEmailVerification::userEmailSend($user);
|
||||
throw new ApiException('您的帐号已注册过,请验证邮箱', ['code' => 'email']);
|
||||
}
|
||||
throw new ApiException('邮箱地址已存在');
|
||||
}
|
||||
//密码
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Module\Base;
|
||||
use Carbon\Carbon;
|
||||
use Guanguans\Notify\Factory;
|
||||
use Guanguans\Notify\Messages\EmailMessage;
|
||||
|
||||
/**
|
||||
* App\Models\UserEmailVerification
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $userid 用户id
|
||||
* @property string|null $code 验证参数
|
||||
* @property string|null $email 电子邮箱
|
||||
* @property int|null $status 0-未验证,1-已验证
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @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|UserEmailVerification whereCode($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification whereCreatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification whereEmail($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification whereStatus($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserEmailVerification whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class UserEmailVerification extends AbstractModel
|
||||
{
|
||||
|
||||
/**
|
||||
* 发验证邮箱
|
||||
* @param User $user
|
||||
*/
|
||||
public static function userEmailSend(User $user)
|
||||
{
|
||||
$res = self::whereUserid($user->userid)->where('created_at', '>', Carbon::now()->subMinutes(30))->first();
|
||||
if ($res) return;
|
||||
//删除
|
||||
self::whereUserid($user->userid)->delete();
|
||||
$userEmailVerification = self::createInstance([
|
||||
'userid' => $user->userid,
|
||||
'email' => $user->email,
|
||||
'code' => Base::generatePassword(64),
|
||||
'status' => 0,
|
||||
]);
|
||||
$userEmailVerification->save();
|
||||
|
||||
$setting = Base::setting('emailSetting');
|
||||
$url = Base::fillUrl('single/valid/email') . '?code=' . $userEmailVerification->code;
|
||||
try {
|
||||
if (!Base::isEmail($user->email)) {
|
||||
throw new \Exception("User email '{$user->email}' address error");
|
||||
}
|
||||
$subject = env('APP_NAME') . " 绑定邮箱验证";
|
||||
$content = "<p>{$user->nickname} 您好,您正在绑定 " . env('APP_NAME') . " 的邮箱,请于30分钟之内点击以下链接完成验证 :</p><p style='display: flex; justify-content: center;'><a href='{$url}' target='_blank'>{$url}</a></p>";
|
||||
Factory::mailer()
|
||||
->setDsn("smtp://{$setting['account']}:{$setting['password']}@{$setting['smtp_server']}:{$setting['port']}?verify_peer=0")
|
||||
->setMessage(EmailMessage::create()
|
||||
->from(env('APP_NAME', 'Task') . " <{$setting['account']}>")
|
||||
->to($user->email)
|
||||
->subject($subject)
|
||||
->html($content))
|
||||
->send();
|
||||
} catch (\Exception $e) {
|
||||
if (str_contains($e->getMessage(), "Timed Out")) {
|
||||
throw new ApiException("language.TimedOut");
|
||||
} elseif ($e->getCode() === 550) {
|
||||
throw new ApiException('邮件内容被拒绝,请检查邮箱是否开启接收功能');
|
||||
} else {
|
||||
throw new ApiException($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Module\Base;
|
||||
use Carbon\Carbon;
|
||||
use Guanguans\Notify\Factory;
|
||||
use Guanguans\Notify\Messages\EmailMessage;
|
||||
|
||||
/**
|
||||
* App\Models\UserTransfer
|
||||
*
|
||||
* @property int $id
|
||||
* @property int|null $original_userid 原作者
|
||||
* @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|UserTransfer newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserTransfer newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserTransfer query()
|
||||
* @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)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserTransfer whereOriginalUserid($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|UserTransfer whereUpdatedAt($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class UserTransfer extends AbstractModel
|
||||
{
|
||||
|
||||
/**
|
||||
* 开始移交
|
||||
* @return void
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
// 移交项目身份
|
||||
ProjectUser::transfer($this->original_userid, $this->new_userid);
|
||||
// 移交任务身份
|
||||
ProjectTaskUser::transfer($this->original_userid, $this->new_userid);
|
||||
// 移交文件
|
||||
File::transfer($this->original_userid, $this->new_userid);
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,14 @@ namespace App\Models;
|
||||
|
||||
|
||||
/**
|
||||
* App\Models\WebSocket
|
||||
* Class WebSocket
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property string $key
|
||||
* @property string|null $fd
|
||||
* @property string|null $path
|
||||
* @property int|null $userid
|
||||
* @property string|null $path
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocket newModelQuery()
|
||||
|
||||
@@ -3,20 +3,18 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Tasks\PushTask;
|
||||
use Carbon\Carbon;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* App\Models\WebSocketDialog
|
||||
* Class WebSocketDialog
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property string|null $type 对话类型
|
||||
* @property string|null $group_type 聊天室类型
|
||||
* @property string|null $name 对话名称
|
||||
* @property string|null $last_at 最后消息时间
|
||||
* @property int|null $owner_id 群主用户ID
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||
@@ -32,7 +30,6 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @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 whereName($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereOwnerId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereType($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialog whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|WebSocketDialog withTrashed()
|
||||
@@ -51,93 +48,6 @@ class WebSocketDialog extends AbstractModel
|
||||
return $this->hasMany(WebSocketDialogUser::class, 'dialog_id', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化对话
|
||||
* @param int $userid 会员ID
|
||||
* @return $this
|
||||
*/
|
||||
public function formatData($userid)
|
||||
{
|
||||
// 最后消息
|
||||
$last_msg = WebSocketDialogMsg::whereDialogId($this->id)->orderByDesc('id')->first();
|
||||
$this->last_msg = $last_msg;
|
||||
// 未读信息
|
||||
$unreadBuilder = WebSocketDialogMsgRead::whereDialogId($this->id)->whereUserid($userid)->whereReadAt(null);
|
||||
$this->unread = $unreadBuilder->count();
|
||||
$this->mention = $unreadBuilder->whereMention(1)->count();
|
||||
$this->mark_unread = $this->mark_unread ?? WebSocketDialogUser::whereDialogId($this->id)->whereUserid($userid)->value('mark_unread');
|
||||
// 对话人数
|
||||
$builder = WebSocketDialogUser::whereDialogId($this->id);
|
||||
$this->people = $builder->count();
|
||||
// 对方信息
|
||||
$this->dialog_user = null;
|
||||
$this->group_info = null;
|
||||
$this->top_at = $this->top_at ?? WebSocketDialogUser::whereDialogId($this->id)->whereUserid($userid)->value('top_at');
|
||||
switch ($this->type) {
|
||||
case "user":
|
||||
$dialog_user = $builder->where('userid', '!=', $userid)->first();
|
||||
$this->name = User::userid2nickname($dialog_user->userid);
|
||||
$this->dialog_user = $dialog_user;
|
||||
break;
|
||||
case "group":
|
||||
if ($this->group_type === 'project') {
|
||||
$this->group_info = Project::withTrashed()->select(['id', 'name', 'archived_at', 'deleted_at'])->whereDialogId($this->id)->first()?->cancelAppend()->cancelHidden();
|
||||
$this->name = $this->group_info ? $this->group_info->name : '';
|
||||
} elseif ($this->group_type === 'task') {
|
||||
$this->group_info = ProjectTask::withTrashed()->select(['id', 'name', 'complete_at', 'archived_at', 'deleted_at'])->whereDialogId($this->id)->first()?->cancelAppend()->cancelHidden();
|
||||
$this->name = $this->group_info ? $this->group_info->name : '';
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入聊天室
|
||||
* @param int|array $userid 加入的会员ID或会员ID组
|
||||
* @return bool
|
||||
*/
|
||||
public function joinGroup($userid)
|
||||
{
|
||||
AbstractModel::transaction(function () use ($userid) {
|
||||
foreach (is_array($userid) ? $userid : [$userid] as $value) {
|
||||
if ($value > 0) {
|
||||
WebSocketDialogUser::updateInsert([
|
||||
'dialog_id' => $this->id,
|
||||
'userid' => $value,
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出聊天室
|
||||
* @param int|array $userid 加入的会员ID或会员ID组
|
||||
* @return bool
|
||||
*/
|
||||
public function exitGroup($userid)
|
||||
{
|
||||
$builder = WebSocketDialogUser::whereDialogId($this->id);
|
||||
if (is_array($userid)) {
|
||||
$builder->whereIn('userid', $userid);
|
||||
} else {
|
||||
$builder->whereUserid($userid);
|
||||
}
|
||||
$builder->chunkById(100, function($list) {
|
||||
/** @var WebSocketDialogUser $item */
|
||||
foreach ($list as $item) {
|
||||
if ($item->userid == $this->owner_id) {
|
||||
// 群主不可退出
|
||||
continue;
|
||||
}
|
||||
$item->delete();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除会话
|
||||
* @return bool
|
||||
@@ -145,76 +55,20 @@ class WebSocketDialog extends AbstractModel
|
||||
public function deleteDialog()
|
||||
{
|
||||
AbstractModel::transaction(function () {
|
||||
WebSocketDialogMsgRead::whereDialogId($this->id)
|
||||
->whereNull('read_at')
|
||||
->chunkById(100, function ($list) {
|
||||
WebSocketDialogMsgRead::onlyMarkRead($list);
|
||||
});
|
||||
WebSocketDialogMsgRead::whereDialogId($this->id)->whereNull('read_at')->update([
|
||||
'read_at' => Carbon::now()
|
||||
]);
|
||||
$this->delete();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 还原会话
|
||||
* @return bool
|
||||
*/
|
||||
public function recoveryDialog()
|
||||
{
|
||||
$this->restore();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查群组类型
|
||||
* @return void
|
||||
*/
|
||||
public function checkGroup($groupType = 'user')
|
||||
{
|
||||
if ($this->type !== 'group') {
|
||||
throw new ApiException('仅限群组操作');
|
||||
}
|
||||
if ($this->group_type !== $groupType) {
|
||||
throw new ApiException('操作的群组类型错误');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送消息
|
||||
* @param $action
|
||||
* @param array $data 发送内容,默认为[id=>项目ID]
|
||||
* @param array $userid 指定会员,默认为群组所有成员
|
||||
* @return void
|
||||
*/
|
||||
public function pushMsg($action, $data = null, $userid = null)
|
||||
{
|
||||
if ($data === null) {
|
||||
$data = ['id' => $this->id];
|
||||
}
|
||||
//
|
||||
if ($userid === null) {
|
||||
$userid = $this->dialogUser->pluck('userid')->toArray();
|
||||
}
|
||||
//
|
||||
$params = [
|
||||
'userid' => $userid,
|
||||
'msg' => [
|
||||
'type' => 'dialog',
|
||||
'mode' => $action,
|
||||
'data' => $data,
|
||||
]
|
||||
];
|
||||
$task = new PushTask($params, false);
|
||||
Task::deliver($task);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对话(同时检验对话身份)
|
||||
* @param $dialog_id
|
||||
* @param bool $checkOwner 是否校验群组身份
|
||||
* @return self
|
||||
*/
|
||||
public static function checkDialog($dialog_id, $checkOwner = false)
|
||||
public static function checkDialog($dialog_id)
|
||||
{
|
||||
$dialog = WebSocketDialog::find($dialog_id);
|
||||
if (empty($dialog)) {
|
||||
@@ -222,10 +76,6 @@ class WebSocketDialog extends AbstractModel
|
||||
}
|
||||
//
|
||||
$userid = User::userid();
|
||||
if ($checkOwner === true && $dialog->owner_id != $userid) {
|
||||
throw new ApiException('仅限群主操作');
|
||||
}
|
||||
//
|
||||
if ($dialog->type === 'group' && $dialog->group_type === 'task') {
|
||||
// 任务群对话校验是否在项目内
|
||||
$project_id = intval(ProjectTask::whereDialogId($dialog->id)->value('project_id'));
|
||||
@@ -236,7 +86,48 @@ class WebSocketDialog extends AbstractModel
|
||||
}
|
||||
}
|
||||
if (!WebSocketDialogUser::whereDialogId($dialog->id)->whereUserid($userid)->exists()) {
|
||||
throw new ApiException('不在成员列表内', ['dialog_id' => $dialog_id], -4003);
|
||||
throw new ApiException('不在成员列表内');
|
||||
}
|
||||
return $dialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化对话
|
||||
* @param WebSocketDialog $dialog
|
||||
* @param int $userid 会员ID
|
||||
* @return self|null
|
||||
*/
|
||||
public static function formatData(WebSocketDialog $dialog, $userid)
|
||||
{
|
||||
if (empty($dialog)) {
|
||||
return null;
|
||||
}
|
||||
// 最后消息
|
||||
$last_msg = WebSocketDialogMsg::whereDialogId($dialog->id)->orderByDesc('id')->first();
|
||||
$dialog->last_msg = $last_msg;
|
||||
// 未读信息
|
||||
$dialog->unread = WebSocketDialogMsgRead::whereDialogId($dialog->id)->whereUserid($userid)->whereReadAt(null)->count();
|
||||
// 对话人数
|
||||
$builder = WebSocketDialogUser::whereDialogId($dialog->id);
|
||||
$dialog->people = $builder->count();
|
||||
// 对方信息
|
||||
$dialog->dialog_user = null;
|
||||
$dialog->group_info = null;
|
||||
switch ($dialog->type) {
|
||||
case "user":
|
||||
$dialog_user = $builder->where('userid', '!=', $userid)->first();
|
||||
$dialog->name = User::userid2nickname($dialog_user->userid);
|
||||
$dialog->dialog_user = $dialog_user;
|
||||
break;
|
||||
case "group":
|
||||
if ($dialog->group_type === 'project') {
|
||||
$dialog->group_info = Project::withTrashed()->select(['id', 'name'])->whereDialogId($dialog->id)->first();
|
||||
$dialog->name = $dialog->group_info ? $dialog->group_info->name : '';
|
||||
} elseif ($dialog->group_type === 'task') {
|
||||
$dialog->group_info = ProjectTask::withTrashed()->select(['id', 'name'])->whereDialogId($dialog->id)->first();
|
||||
$dialog->name = $dialog->group_info ? $dialog->group_info->name : '';
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $dialog;
|
||||
}
|
||||
@@ -244,20 +135,17 @@ class WebSocketDialog extends AbstractModel
|
||||
/**
|
||||
* 创建聊天室
|
||||
* @param string $name 聊天室名称
|
||||
* @param int|array $userid 加入的会员ID(组)
|
||||
* @param int|array $userid 加入的会员ID或会员ID组
|
||||
* @param string $group_type 聊天室类型
|
||||
* @param int $owner_id 群主会员ID
|
||||
* @return self|null
|
||||
*/
|
||||
public static function createGroup($name, $userid, $group_type = '', $owner_id = 0)
|
||||
public static function createGroup($name, $userid, $group_type = '')
|
||||
{
|
||||
return AbstractModel::transaction(function () use ($owner_id, $userid, $group_type, $name) {
|
||||
return AbstractModel::transaction(function () use ($userid, $group_type, $name) {
|
||||
$dialog = self::createInstance([
|
||||
'type' => 'group',
|
||||
'name' => $name ?: '',
|
||||
'group_type' => $group_type,
|
||||
'owner_id' => $owner_id,
|
||||
'last_at' => $group_type === 'user' ? Carbon::now() : null,
|
||||
]);
|
||||
$dialog->save();
|
||||
foreach (is_array($userid) ? $userid : [$userid] as $value) {
|
||||
@@ -272,6 +160,47 @@ class WebSocketDialog extends AbstractModel
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入聊天室
|
||||
* @param int $dialog_id 会话ID(即 聊天室ID)
|
||||
* @param int|array $userid 加入的会员ID或会员ID组
|
||||
* @return bool
|
||||
*/
|
||||
public static function joinGroup($dialog_id, $userid)
|
||||
{
|
||||
$dialog = self::whereId($dialog_id)->whereType('group')->first();
|
||||
if (empty($dialog)) {
|
||||
return false;
|
||||
}
|
||||
AbstractModel::transaction(function () use ($dialog, $userid) {
|
||||
foreach (is_array($userid) ? $userid : [$userid] as $value) {
|
||||
if ($value > 0) {
|
||||
WebSocketDialogUser::createInstance([
|
||||
'dialog_id' => $dialog->id,
|
||||
'userid' => $value,
|
||||
])->save();
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出聊天室
|
||||
* @param int $dialog_id 会话ID(即 聊天室ID)
|
||||
* @param int|array $userid 加入的会员ID或会员ID组
|
||||
* @return bool
|
||||
*/
|
||||
public static function exitGroup($dialog_id, $userid)
|
||||
{
|
||||
if (is_array($userid)) {
|
||||
WebSocketDialogUser::whereDialogId($dialog_id)->whereIn('userid', $userid)->delete();
|
||||
} else {
|
||||
WebSocketDialogUser::whereDialogId($dialog_id)->whereUserid($userid)->delete();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会员对话(没有自动创建)
|
||||
* @param int $userid 会员ID
|
||||
|
||||
@@ -8,11 +8,11 @@ use App\Tasks\PushTask;
|
||||
use App\Tasks\WebSocketDialogMsgTask;
|
||||
use Carbon\Carbon;
|
||||
use Hhxsv5\LaravelS\Swoole\Task\Task;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* App\Models\WebSocketDialogMsg
|
||||
* Class WebSocketDialogMsg
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $dialog_id 对话ID
|
||||
* @property int|null $userid 发送会员ID
|
||||
@@ -22,15 +22,11 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @property int|null $send 发送数量
|
||||
* @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\WebSocketDialog|null $webSocketDialog
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg newQuery()
|
||||
* @method static \Illuminate\Database\Query\Builder|WebSocketDialogMsg onlyTrashed()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg query()
|
||||
* @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 whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereMsg($value)
|
||||
@@ -39,14 +35,10 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereType($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsg whereUserid($value)
|
||||
* @method static \Illuminate\Database\Query\Builder|WebSocketDialogMsg withTrashed()
|
||||
* @method static \Illuminate\Database\Query\Builder|WebSocketDialogMsg withoutTrashed()
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class WebSocketDialogMsg extends AbstractModel
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $appends = [
|
||||
'percentage',
|
||||
];
|
||||
@@ -55,14 +47,6 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
'updated_at',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function webSocketDialog(): \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
{
|
||||
return $this->hasOne(WebSocketDialog::class, 'id', 'dialog_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 阅读占比
|
||||
* @return int|mixed
|
||||
@@ -70,7 +54,11 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
public function getPercentageAttribute()
|
||||
{
|
||||
if (!isset($this->appendattrs['percentage'])) {
|
||||
$this->generatePercentage();
|
||||
if ($this->read > $this->send || empty($this->send)) {
|
||||
$this->appendattrs['percentage'] = 100;
|
||||
} else {
|
||||
$this->appendattrs['percentage'] = intval($this->read / $this->send * 100);
|
||||
}
|
||||
}
|
||||
return $this->appendattrs['percentage'];
|
||||
}
|
||||
@@ -94,22 +82,6 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取占比
|
||||
* @param bool|int $increment 是否新增阅读数
|
||||
* @return int
|
||||
*/
|
||||
public function generatePercentage($increment = false) {
|
||||
if ($increment) {
|
||||
$this->increment('read', is_bool($increment) ? 1 : $increment);
|
||||
}
|
||||
if ($this->read > $this->send || empty($this->send)) {
|
||||
return $this->appendattrs['percentage'] = 100;
|
||||
} else {
|
||||
return $this->appendattrs['percentage'] = intval($this->read / $this->send * 100);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记已送达 同时 告诉发送人已送达
|
||||
* @param $userid
|
||||
@@ -139,17 +111,13 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
if (!$msgRead->read_at) {
|
||||
$msgRead->read_at = Carbon::now();
|
||||
$msgRead->save();
|
||||
$this->generatePercentage(true);
|
||||
$this->increment('read');
|
||||
PushTask::push([
|
||||
'userid' => $this->userid,
|
||||
'msg' => [
|
||||
'type' => 'dialog',
|
||||
'mode' => 'readed',
|
||||
'data' => [
|
||||
'id' => $this->id,
|
||||
'read' => $this->read,
|
||||
'percentage' => $this->percentage,
|
||||
],
|
||||
'mode' => 'update',
|
||||
'data' => $this->toArray(),
|
||||
]
|
||||
]);
|
||||
}
|
||||
@@ -157,93 +125,6 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除消息
|
||||
* @return void
|
||||
*/
|
||||
public function deleteMsg()
|
||||
{
|
||||
$send_dt = Carbon::parse($this->created_at)->addDay();
|
||||
if ($send_dt->lt(Carbon::now())) {
|
||||
throw new ApiException('已超过24小时,此消息不能撤回');
|
||||
}
|
||||
AbstractModel::transaction(function() {
|
||||
$deleteRead = WebSocketDialogMsgRead::whereMsgId($this->id)->whereNull('read_at')->delete(); // 未阅读记录不需要软删除,直接删除即可
|
||||
$this->delete();
|
||||
//
|
||||
$last_msg = null;
|
||||
if ($this->webSocketDialog) {
|
||||
$last_msg = WebSocketDialogMsg::whereDialogId($this->dialog_id)->orderByDesc('id')->first();
|
||||
$this->webSocketDialog->last_at = $last_msg->created_at;
|
||||
$this->webSocketDialog->save();
|
||||
}
|
||||
//
|
||||
$dialog = WebSocketDialog::find($this->dialog_id);
|
||||
if ($dialog) {
|
||||
$userids = $dialog->dialogUser->pluck('userid')->toArray();
|
||||
PushTask::push([
|
||||
'userid' => $userids,
|
||||
'msg' => [
|
||||
'type' => 'dialog',
|
||||
'mode' => 'delete',
|
||||
'data' => [
|
||||
'id' => $this->id,
|
||||
'dialog_id' => $this->dialog_id,
|
||||
'last_msg' => $last_msg,
|
||||
'update_read' => $deleteRead ? 1 : 0
|
||||
],
|
||||
]
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文本消息内容,用于发送前
|
||||
* @param $text
|
||||
* @param $dialog_id
|
||||
* @return mixed|string|string[]
|
||||
*/
|
||||
public static function formatMsg($text, $dialog_id)
|
||||
{
|
||||
// 图片 [:IMAGE:className:width:height:src:alt:]
|
||||
preg_match_all("/<img\s*src=\"data:image\/(png|jpg|jpeg);base64,(.*?)\"(.*?)>(<\/img>)*/s", $text, $matchs);
|
||||
foreach ($matchs[2] as $key => $base64) {
|
||||
$tmpPath = "uploads/chat/" . date("Ym") . "/" . $dialog_id . "/";
|
||||
Base::makeDir(public_path($tmpPath));
|
||||
$tmpPath .= md5s($base64) . "." . $matchs[1][$key];
|
||||
if (file_put_contents(public_path($tmpPath), base64_decode($base64))) {
|
||||
$imagesize = getimagesize(public_path($tmpPath));
|
||||
$text = str_replace($matchs[0][$key], "[:IMAGE:browse:{$imagesize[0]}:{$imagesize[1]}:{$tmpPath}::]", $text);
|
||||
}
|
||||
}
|
||||
// 表情图片
|
||||
preg_match_all("/<img class=\"emoticon\"(.*?)>/s", $text, $matchs);
|
||||
foreach ($matchs[1] as $key => $str) {
|
||||
preg_match("/data-asset=\"(.*?)\"/", $str, $matchAsset);
|
||||
preg_match("/data-name=\"(.*?)\"/", $str, $matchName);
|
||||
if (file_exists(public_path($matchAsset[1]))) {
|
||||
$imagesize = getimagesize(public_path($matchAsset[1]));
|
||||
$text = str_replace($matchs[0][$key], "[:IMAGE:emoticon:{$imagesize[0]}:{$imagesize[1]}:{$matchAsset[1]}:{$matchName[1]}:]", $text);
|
||||
}
|
||||
}
|
||||
// @成员、#任务
|
||||
preg_match_all("/<span class=\"mention\"(.*?)>.*?<\/span>.*?<\/span>.*?<\/span>/s", $text, $matchs);
|
||||
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);
|
||||
$text = str_replace($matchs[0][$key], "[:{$matchChar[1]}:{$matchId[1]}:{$matchValye[1]}:]", $text);
|
||||
}
|
||||
// 过滤标签
|
||||
$text = strip_tags($text, '<blockquote> <strong> <pre> <ol> <ul> <li> <em> <p> <s> <u>');
|
||||
$text = preg_replace("/\<(blockquote|strong|pre|ol|ul|li|em|p|s|u).*?\>/i", "<$1>", $text);
|
||||
$text = preg_replace("/\[:IMAGE:(.*?):(.*?):(.*?):(.*?):(.*?):\]/i", "<img class=\"$1\" width=\"$2\" height=\"$3\" src=\"{{RemoteURL}}$4\" alt=\"$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);
|
||||
return preg_replace("/^(<p><\/p>)+|(<p><\/p>)+$/i", "", $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* @param int $dialog_id 会话ID(即 聊天室ID)
|
||||
|
||||
@@ -2,26 +2,22 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* App\Models\WebSocketDialogMsgRead
|
||||
* Class WebSocketDialogMsgRead
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $dialog_id 对话ID
|
||||
* @property int|null $msg_id 消息ID
|
||||
* @property int|null $userid 发送会员ID
|
||||
* @property int|null $mention 是否提及(被@)
|
||||
* @property int|null $after 在阅读之后才添加的记录
|
||||
* @property string|null $read_at 阅读时间
|
||||
* @property-read \App\Models\WebSocketDialogMsg|null $webSocketDialogMsg
|
||||
* @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|WebSocketDialogMsgRead whereAfter($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead whereDialogId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead whereMention($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead whereMsgId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead whereReadAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogMsgRead whereUserid($value)
|
||||
@@ -34,38 +30,4 @@ class WebSocketDialogMsgRead extends AbstractModel
|
||||
parent::__construct($attributes);
|
||||
$this->timestamps = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function webSocketDialogMsg(): \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
{
|
||||
return $this->hasOne(WebSocketDialogMsg::class, 'id', 'msg_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅标记成阅读
|
||||
* @param $list
|
||||
* @return void
|
||||
*/
|
||||
public static function onlyMarkRead($list)
|
||||
{
|
||||
$dialogMsg = [];
|
||||
/** @var WebSocketDialogMsgRead $item */
|
||||
foreach ($list as $item) {
|
||||
$item->read_at = Carbon::now();
|
||||
$item->save();
|
||||
if (isset($dialogMsg[$item->msg_id])) {
|
||||
$dialogMsg[$item->msg_id]['readNum']++;
|
||||
} else {
|
||||
$dialogMsg[$item->msg_id] = [
|
||||
'dialogMsg' => $item->webSocketDialogMsg,
|
||||
'readNum' => 1
|
||||
];
|
||||
}
|
||||
}
|
||||
foreach ($dialogMsg as $item) {
|
||||
$item['dialogMsg']?->generatePercentage($item['readNum']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\WebSocketDialogUser
|
||||
* Class WebSocketDialogUser
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property int|null $dialog_id 对话ID
|
||||
* @property int|null $userid 会员ID
|
||||
* @property string|null $top_at 置顶时间
|
||||
* @property int|null $mark_unread 是否标记为未读:0否,1是
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser newModelQuery()
|
||||
@@ -18,8 +17,6 @@ namespace App\Models;
|
||||
* @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 whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereMarkUnread($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereTopAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereUpdatedAt($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|WebSocketDialogUser whereUserid($value)
|
||||
* @mixin \Eloquent
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* App\Models\WebSocketTmpMsg
|
||||
* Class WebSocketTmpMsg
|
||||
*
|
||||
* @package App\Models
|
||||
* @property int $id
|
||||
* @property string|null $md5 MD5(会员ID-消息)
|
||||
* @property string|null $msg 详细消息
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Module;
|
||||
|
||||
use App\Exceptions\ApiException;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Tmp;
|
||||
use Cache;
|
||||
@@ -12,7 +11,6 @@ use Illuminate\Support\Facades\Config;
|
||||
use Redirect;
|
||||
use Request;
|
||||
use Storage;
|
||||
use Validator;
|
||||
|
||||
class Base
|
||||
{
|
||||
@@ -60,55 +58,20 @@ class Base
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取package配置文件
|
||||
* @return array
|
||||
*/
|
||||
public static function getPackage()
|
||||
{
|
||||
return Cache::remember("Base::package", now()->addSeconds(10), function () {
|
||||
$file = base_path('package.json');
|
||||
if (file_exists($file)) {
|
||||
$package = json_decode(file_get_contents($file), true);
|
||||
return is_array($package) ? $package : [];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取版本号
|
||||
* @return string
|
||||
*/
|
||||
public static function getVersion()
|
||||
{
|
||||
$package = self::getPackage();
|
||||
return $package['version'] ?? '1.0.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端版本号
|
||||
* @return string
|
||||
*/
|
||||
public static function getClientVersion()
|
||||
{
|
||||
global $_A;
|
||||
if (!isset($_A["__static_client_version"])) {
|
||||
$_A["__static_client_version"] = Request::header('version') ?: '0.0.1';
|
||||
}
|
||||
return $_A["__static_client_version"];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查客户端版本
|
||||
* @param string $min 最小版本
|
||||
* @return void
|
||||
*/
|
||||
public static function checkClientVersion($min)
|
||||
{
|
||||
if (version_compare(Base::getClientVersion(), $min, '<')) {
|
||||
throw new ApiException('当前版本 (v' . Base::getClientVersion() . ') 过低');
|
||||
}
|
||||
return Cache::remember("Base::version", now()->addSeconds(10), function () {
|
||||
$file = base_path('package.json');
|
||||
if (file_exists($file)) {
|
||||
$packageArray = json_decode(file_get_contents($file), true);
|
||||
return $packageArray['version'] ?? '1.0.0';
|
||||
}
|
||||
return '1.0.0';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,15 +316,19 @@ class Base
|
||||
{
|
||||
if (strtolower($charset) == 'utf-8') {
|
||||
if (Base::getStrlen($string) <= $length) return $string;
|
||||
$strcut = Base::utf8Substr($string, $length, $start);
|
||||
$strcut = str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $string);
|
||||
$strcut = Base::utf8Substr($strcut, $length, $start);
|
||||
$strcut = str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $strcut);
|
||||
return $strcut . $dot;
|
||||
} else {
|
||||
$length = $length * 2;
|
||||
if (strlen($string) <= $length) return $string;
|
||||
$string = str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $string);
|
||||
$strcut = '';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$strcut .= ord($string[$i]) > 127 ? $string[$i] . $string[++$i] : $string[$i];
|
||||
}
|
||||
$strcut = str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $strcut);
|
||||
}
|
||||
return $strcut . $dot;
|
||||
}
|
||||
@@ -717,20 +684,24 @@ class Base
|
||||
/**
|
||||
* 判断两个地址域名是否相同
|
||||
* @param string $var1
|
||||
* @param string|array $var2
|
||||
* @param string $var2
|
||||
* @return bool
|
||||
*/
|
||||
public static function hostContrast($var1, $var2)
|
||||
{
|
||||
$arr1 = parse_url($var1);
|
||||
$host1 = $arr1['host'] ?? $var1;
|
||||
$arr2 = parse_url($var2);
|
||||
//
|
||||
$host2 = [];
|
||||
foreach (is_array($var2) ? $var2 : [$var2] as $url) {
|
||||
$arr2 = parse_url($url);
|
||||
$host2[] = $arr2['host'] ?? $url;
|
||||
$host1 = $var1;
|
||||
if (isset($arr1['host'])) {
|
||||
$host1 = $arr1['host'];
|
||||
}
|
||||
return in_array($host1, $host2);
|
||||
//
|
||||
$host2 = $var2;
|
||||
if (isset($arr2['host'])) {
|
||||
$host2 = $arr2['host'];
|
||||
}
|
||||
return $host1 == $host2;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -754,7 +725,6 @@ class Base
|
||||
*/
|
||||
public static function fillUrl($str = '')
|
||||
{
|
||||
global $_A;
|
||||
if (is_array($str)) {
|
||||
foreach ($str as $key => $item) {
|
||||
$str[$key] = Base::fillUrl($item);
|
||||
@@ -773,12 +743,9 @@ class Base
|
||||
) {
|
||||
return $str;
|
||||
} else {
|
||||
if ($_A['__fill_url_remote_url'] === true) {
|
||||
return "{{RemoteURL}}" . $str;
|
||||
}
|
||||
try {
|
||||
return url($str);
|
||||
} catch (\Throwable) {
|
||||
} catch (\Throwable $e) {
|
||||
return self::getSchemeAndHost() . "/" . $str;
|
||||
}
|
||||
}
|
||||
@@ -799,7 +766,7 @@ class Base
|
||||
}
|
||||
try {
|
||||
$find = url('');
|
||||
} catch (\Throwable) {
|
||||
} catch (\Throwable $e) {
|
||||
$find = self::getSchemeAndHost();
|
||||
}
|
||||
return Base::leftDelete($str, $find . '/');
|
||||
@@ -815,31 +782,6 @@ class Base
|
||||
return $scheme.($_SERVER['HTTP_HOST'] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* 地址后拼接参数
|
||||
* @param $url
|
||||
* @param $parames
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function urlAddparameter($url, $parames)
|
||||
{
|
||||
if ($parames && is_array($parames)) {
|
||||
$array = [];
|
||||
foreach ($parames as $key => $val) {
|
||||
$array[] = $key . "=" . $val;
|
||||
}
|
||||
if ($array) {
|
||||
$query = implode("&", $array);
|
||||
if (str_contains($url, "?")) {
|
||||
$url .= "&" . $query;
|
||||
} else {
|
||||
$url .= "?" . $query;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化内容图片地址
|
||||
* @param $content
|
||||
@@ -888,16 +830,13 @@ class Base
|
||||
/**
|
||||
* 数组只保留数字的
|
||||
* @param $array
|
||||
* @param bool $int 是否格式化值
|
||||
* @return array
|
||||
*/
|
||||
public static function arrayRetainInt($array, $int = false)
|
||||
public static function arrayRetainInt($array)
|
||||
{
|
||||
foreach ($array as $k => $v) {
|
||||
if (!is_numeric($v)) {
|
||||
unset($array[$k]);
|
||||
} elseif ($int === true) {
|
||||
$array[$k] = intval($v);
|
||||
}
|
||||
}
|
||||
return array_values($array);
|
||||
@@ -992,16 +931,13 @@ class Base
|
||||
|
||||
/**
|
||||
* 检测邮箱格式
|
||||
* @param $str
|
||||
* @return bool
|
||||
* @param string $str 需要检测的字符串
|
||||
* @return int
|
||||
*/
|
||||
public static function isEmail($str)
|
||||
public static function isMail($str)
|
||||
{
|
||||
if (filter_var($str, FILTER_VALIDATE_EMAIL)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
$RegExp = '/^[a-z0-9][a-z\.0-9-_]+@[a-z0-9_-]+(?:\.[a-z]{0,3}\.[a-z]{0,2}|\.[a-z]{0,3}|\.[a-z]{0,2})$/i';
|
||||
return preg_match($RegExp, $str);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1217,12 +1153,11 @@ class Base
|
||||
|
||||
/**
|
||||
* 获取或设置
|
||||
* @param $setname // 配置名称
|
||||
* @param bool $array // 保存内容
|
||||
* @param false $isUpdate // 保存内容为更新模式,默认否
|
||||
* @param $setname //配置名称
|
||||
* @param bool $array //保存内容
|
||||
* @return array
|
||||
*/
|
||||
public static function setting($setname, $array = false, $isUpdate = false)
|
||||
public static function setting($setname, $array = false)
|
||||
{
|
||||
global $_A;
|
||||
if (empty($setname)) {
|
||||
@@ -1233,19 +1168,15 @@ class Base
|
||||
}
|
||||
$setting = [];
|
||||
$row = Setting::whereName($setname)->first();
|
||||
if ($row) {
|
||||
if (!empty($row)) {
|
||||
$setting = Base::string2array($row->setting);
|
||||
} else {
|
||||
$row = Setting::createInstance(['name' => $setname]);
|
||||
$row->save();
|
||||
}
|
||||
if ($array !== false) {
|
||||
if ($isUpdate && is_array($array)) {
|
||||
$setting = array_merge($setting, $array);
|
||||
} else {
|
||||
$setting = $array;
|
||||
}
|
||||
$row->updateInstance(['setting' => $setting]);
|
||||
$setting = $array;
|
||||
$row->updateInstance(['setting' => $array]);
|
||||
$row->save();
|
||||
}
|
||||
$_A["__static_setting_" . $setname] = $setting;
|
||||
@@ -1628,7 +1559,7 @@ class Base
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户名、邮箱、手机帐号、银行卡号中间字符串以*隐藏
|
||||
* 用户名、邮箱、手机账号、银行卡号中间字符串以*隐藏
|
||||
* @param $str
|
||||
* @return string
|
||||
*/
|
||||
@@ -1727,46 +1658,24 @@ class Base
|
||||
*/
|
||||
public static function timeDiff($s, $e)
|
||||
{
|
||||
$time = $e - $s;
|
||||
$days = 0;
|
||||
if ($time >= 86400) { // 如果大于1天
|
||||
$days = (int)($time / 86400);
|
||||
$time = $time % 86400; // 计算天后剩余的毫秒数
|
||||
$d = $e - $s;
|
||||
if ($d > 86400) {
|
||||
$day = floor($d / 86400);
|
||||
$hour = ceil(($d - ($day * 86400)) / 3600);
|
||||
if ($hour > 0) {
|
||||
return $day . '天' . $hour . '小时';
|
||||
} else {
|
||||
return $day . '天';
|
||||
}
|
||||
} elseif ($d > 3600) {
|
||||
return ceil($d / 3600) . '小时';
|
||||
} elseif ($d > 60) {
|
||||
return ceil($d / 60) . '分钟';
|
||||
} elseif ($d > 1) {
|
||||
return '1分钟内';
|
||||
} else {
|
||||
return '0秒';
|
||||
}
|
||||
$hours = 0;
|
||||
if ($time >= 3600) { // 如果大于1小时
|
||||
$hours = (int)($time / 3600);
|
||||
$time = $time % 3600; // 计算小时后剩余的毫秒数
|
||||
}
|
||||
$minutes = ceil($time / 60); // 剩下的毫秒数都算作分
|
||||
$daysStr = $days > 0 ? $days . '天' : '';
|
||||
$hoursStr = ($hours > 0 || ($days > 0 && $minutes > 0)) ? $hours . '时' : '';
|
||||
$minuteStr = ($minutes > 0) ? $minutes . '分' : '';
|
||||
return $daysStr . $hoursStr . $minuteStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间秒数格式化
|
||||
* @param int $time 时间秒数
|
||||
* @return string
|
||||
*/
|
||||
public static function timeFormat($time)
|
||||
{
|
||||
$days = 0;
|
||||
if ($time >= 86400) { // 如果大于1天
|
||||
$days = (int)($time / 86400);
|
||||
$time = $time % 86400; // 计算天后剩余的毫秒数
|
||||
}
|
||||
$hours = 0;
|
||||
if ($time >= 3600) { // 如果大于1小时
|
||||
$hours = (int)($time / 3600);
|
||||
$time = $time % 3600; // 计算小时后剩余的毫秒数
|
||||
}
|
||||
$minutes = ceil($time / 60); // 剩下的毫秒数都算作分
|
||||
$daysStr = $days > 0 ? $days . '天' : '';
|
||||
$hoursStr = ($hours > 0 || ($days > 0 && $minutes > 0)) ? $hours . '时' : '';
|
||||
$minuteStr = ($minutes > 0) ? $minutes . '分' : '';
|
||||
return $daysStr . $hoursStr . $minuteStr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2196,7 +2105,7 @@ class Base
|
||||
if ($width > 0 || $height > 0) {
|
||||
$scaleName = "_{WIDTH}x{HEIGHT}";
|
||||
if (isset($param['scale'][2])) {
|
||||
$scaleName .= "_c{$param['scale'][2]}";
|
||||
$scaleName .= $param['scale'][2];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2307,7 +2216,7 @@ class Base
|
||||
$type = ['zip'];
|
||||
break;
|
||||
case 'file':
|
||||
$type = ['jpg', 'jpeg', 'png', 'gif', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'esp', 'pdf', 'rar', 'zip', 'gz', 'ai', 'avi', 'bmp', 'cdr', 'eps', 'mov', 'mp3', 'mp4', 'pr', 'psd', 'svg', 'tif'];
|
||||
$type = ['jpg', 'jpeg', 'png', 'gif', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'esp', 'pdf', 'rar', 'zip', 'gz'];
|
||||
break;
|
||||
case 'firmware':
|
||||
$type = ['img', 'tar', 'bin'];
|
||||
@@ -2315,14 +2224,8 @@ class Base
|
||||
case 'md':
|
||||
$type = ['md'];
|
||||
break;
|
||||
case 'desktop':
|
||||
$type = ['yml', 'yaml', 'dmg', 'pkg', 'blockmap', 'zip', 'exe', 'msi'];
|
||||
break;
|
||||
case 'more':
|
||||
$type = [
|
||||
'text', 'md', 'markdown',
|
||||
'drawio',
|
||||
'mind',
|
||||
'docx', 'wps', 'doc', 'xls', 'xlsx', 'ppt', 'pptx',
|
||||
'jpg', 'jpeg', 'png', 'gif', 'bmp', 'ico', 'raw',
|
||||
'rar', 'zip', 'jar', '7-zip', 'tar', 'gzip', '7z',
|
||||
@@ -2331,17 +2234,10 @@ class Base
|
||||
'ofd',
|
||||
'pdf',
|
||||
'txt',
|
||||
'htaccess', 'htgroups', 'htpasswd', 'conf', 'bat', 'cmd', 'cpp', 'c', 'cc', 'cxx', 'h', 'hh', 'hpp', 'ino', 'cs', 'css',
|
||||
'dockerfile', 'go', 'golang', 'html', 'htm', 'xhtml', 'vue', 'we', 'wpy', 'java', 'js', 'jsm', 'jsx', 'json', 'jsp', 'less', 'lua', 'makefile', 'gnumakefile',
|
||||
'ocamlmakefile', 'make', 'mysql', 'nginx', 'ini', 'cfg', 'prefs', 'm', 'mm', 'pl', 'pm', 'p6', 'pl6', 'pm6', 'pgsql', 'php',
|
||||
'inc', 'phtml', 'shtml', 'php3', 'php4', 'php5', 'phps', 'phpt', 'aw', 'ctp', 'module', 'ps1', 'py', 'r', 'rb', 'ru', 'gemspec', 'rake', 'guardfile', 'rakefile',
|
||||
'gemfile', 'rs', 'sass', 'scss', 'sh', 'bash', 'bashrc', 'sql', 'sqlserver', 'swift', 'ts', 'typescript', 'str', 'vbs', 'vb', 'v', 'vh', 'sv', 'svh', 'xml',
|
||||
'rdf', 'rss', 'wsdl', 'xslt', 'atom', 'mathml', 'mml', 'xul', 'xbl', 'xaml', 'yaml', 'yml',
|
||||
'asp', 'properties', 'gitignore', 'log', 'bas', 'prg', 'python', 'ftl', 'aspx',
|
||||
'html', 'htm', 'asp', 'jsp', 'xml', 'json', 'properties', 'md', 'gitignore', 'log', 'java', 'py', 'c', 'cpp', 'sql', 'sh', 'bat', 'm', 'bas', 'prg', 'cmd',
|
||||
'php', 'go', 'python', 'js', 'ftl', 'css', 'lua', 'rb', 'yaml', 'yml', 'h', 'cs', 'aspx',
|
||||
'mp3', 'wav', 'mp4', 'flv',
|
||||
'avi', 'mov', 'wmv', 'mkv', '3gp', 'rm',
|
||||
'xmind',
|
||||
'rp',
|
||||
];
|
||||
break;
|
||||
default:
|
||||
@@ -2360,9 +2256,7 @@ class Base
|
||||
$fileSize = 0;
|
||||
}
|
||||
$scaleName = "";
|
||||
if ($param['fileName'] === true) {
|
||||
$fileName = $file->getClientOriginalName();
|
||||
} elseif ($param['fileName']) {
|
||||
if ($param['fileName']) {
|
||||
$fileName = $param['fileName'];
|
||||
} else {
|
||||
if ($param['scale'] && is_array($param['scale'])) {
|
||||
@@ -2370,7 +2264,7 @@ class Base
|
||||
if ($width > 0 || $height > 0) {
|
||||
$scaleName = "_{WIDTH}x{HEIGHT}";
|
||||
if (isset($param['scale'][2])) {
|
||||
$scaleName .= "_c{$param['scale'][2]}";
|
||||
$scaleName .= $param['scale'][2];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2465,37 +2359,6 @@ class Base
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件移动
|
||||
* @param array $uploadResult
|
||||
* @param string $newPath "/" 结尾
|
||||
* @return array
|
||||
*/
|
||||
public static function uploadMove($uploadResult, $newPath)
|
||||
{
|
||||
if (str_ends_with($newPath, "/") && file_exists($uploadResult['file'])) {
|
||||
Base::makeDir(public_path($newPath));
|
||||
$oldPath = dirname($uploadResult['path']) . "/";
|
||||
$newFile = str_replace($oldPath, $newPath, $uploadResult['file']);
|
||||
if (rename($uploadResult['file'], $newFile)) {
|
||||
$oldUrl = $uploadResult['url'];
|
||||
$uploadResult['file'] = $newFile;
|
||||
$uploadResult['path'] = str_replace($oldPath, $newPath, $uploadResult['path']);
|
||||
$uploadResult['url'] = str_replace($oldPath, $newPath, $uploadResult['url']);
|
||||
if ($uploadResult['thumb'] == $oldUrl) {
|
||||
$uploadResult['thumb'] = $uploadResult['url'];
|
||||
} elseif ($uploadResult['thumb']) {
|
||||
$oldThumb = substr($uploadResult['thumb'], strpos($uploadResult['thumb'], $newPath));
|
||||
$newThumb = str_replace($oldPath, $newPath, $oldThumb);
|
||||
if (file_exists(public_path($oldThumb)) && rename(public_path($oldThumb), public_path($newThumb))) {
|
||||
$uploadResult['thumb'] = str_replace($oldPath, $newPath, $uploadResult['thumb']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $uploadResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成缩略图
|
||||
* @param string $src_img 源图绝对完整地址{带文件名及后缀名}
|
||||
@@ -2767,19 +2630,16 @@ class Base
|
||||
/**
|
||||
* 遍历获取文件
|
||||
* @param $dir
|
||||
* @param bool $subdirectory 是否遍历子目录
|
||||
* @return array
|
||||
*/
|
||||
public static function readDir($dir, $subdirectory = true)
|
||||
public static function readDir($dir)
|
||||
{
|
||||
$files = array();
|
||||
$dir_list = scandir($dir);
|
||||
foreach ($dir_list as $file) {
|
||||
if ($file != '..' && $file != '.') {
|
||||
if (is_dir($dir . '/' . $file)) {
|
||||
if ($subdirectory) {
|
||||
$files = array_merge($files, self::readDir($dir . '/' . $file, $subdirectory));
|
||||
}
|
||||
$files = array_merge($files, self::readDir($dir . '/' . $file));
|
||||
} else {
|
||||
$files[] = $dir . "/" . $file;
|
||||
}
|
||||
@@ -3008,54 +2868,4 @@ class Base
|
||||
$matrix = array_unique($matrix, SORT_REGULAR);
|
||||
return array_merge($matrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字节转格式
|
||||
* @param $bytes
|
||||
* @return string
|
||||
*/
|
||||
public static function readableBytes($bytes)
|
||||
{
|
||||
$i = floor(log($bytes) / log(1024));
|
||||
$sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
return sprintf('%.02F', $bytes / pow(1024, $i)) * 1 . ' ' . $sizes[$i];
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除emoji表情
|
||||
* @param $str
|
||||
* @return string|string[]|null
|
||||
*/
|
||||
public static function filterEmoji($str)
|
||||
{
|
||||
return preg_replace_callback(
|
||||
'/./u',
|
||||
function (array $match) {
|
||||
return strlen($match[0]) >= 4 ? '' : $match[0];
|
||||
},
|
||||
$str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一验证器
|
||||
* @param $data
|
||||
* @param $messages
|
||||
*/
|
||||
public static function validator($data, $messages) {
|
||||
$rules = [];
|
||||
foreach ($messages as $key => $item) {
|
||||
$keys = explode(".", $key);
|
||||
if (isset($keys[1])) {
|
||||
if (isset($rules[$keys[0]])) {
|
||||
$rules[$keys[0]] = $rules[$keys[0]] . '|' . $keys[1];
|
||||
} else {
|
||||
$rules[$keys[0]] = $keys[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
$validator = Validator::make($data, $rules, $messages);
|
||||
if ($validator->fails()) {
|
||||
throw new ApiException($validator->errors()->first());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Module;
|
||||
|
||||
use Excel;
|
||||
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||
use Maatwebsite\Excel\Concerns\WithEvents;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;
|
||||
use Maatwebsite\Excel\Concerns\WithTitle;
|
||||
use Maatwebsite\Excel\Events\AfterSheet;
|
||||
use PhpOffice\PhpSpreadsheet\Cell\DataValidation;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Exception;
|
||||
|
||||
class BillExport implements WithHeadings, WithEvents, FromCollection, WithTitle, WithStrictNullComparison
|
||||
{
|
||||
public $title;
|
||||
public $headings = [];
|
||||
public $data = [];
|
||||
public $typeLists = [];
|
||||
public $typeNumber = 0;
|
||||
|
||||
public function __construct($title, array $data)
|
||||
{
|
||||
$this->title = $title;
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public static function create($data = [], $title = "Sheet1") {
|
||||
if (is_string($data)) {
|
||||
list($title, $data) = [$data, $title];
|
||||
}
|
||||
if (!is_array($data)) {
|
||||
$data = [];
|
||||
}
|
||||
return new BillExport($title, $data);
|
||||
}
|
||||
|
||||
public function setTitle($title) {
|
||||
$this->title = $title;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHeadings(array $headings) {
|
||||
$this->headings = $headings;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setData(array $data) {
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setTypeList(array $typeList, $number = 0) {
|
||||
$this->typeLists = $typeList;
|
||||
$this->typeNumber = $number;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function store($fileName = '') {
|
||||
if (empty($fileName)) {
|
||||
$fileName = date("YmdHis") . '.xls';
|
||||
}
|
||||
try {
|
||||
return Excel::store($this, $fileName);
|
||||
} catch (Exception $e) {
|
||||
return "导出错误:" . $e->getMessage();
|
||||
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
|
||||
return "导出错误:" . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
public function download($fileName = '') {
|
||||
if (empty($fileName)) {
|
||||
$fileName = date("YmdHis") . '.xls';
|
||||
}
|
||||
try {
|
||||
return Excel::download($this, $fileName);
|
||||
} catch (Exception $e) {
|
||||
return "导出错误:" . $e->getMessage();
|
||||
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
|
||||
return "导出错误:" . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出的文件标题
|
||||
* @return string
|
||||
*/
|
||||
public function title(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题行
|
||||
* @return array
|
||||
*/
|
||||
public function headings(): array
|
||||
{
|
||||
return $this->headings;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出的内容
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function collection()
|
||||
{
|
||||
return collect($this->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置单元格事件
|
||||
* @return array
|
||||
*/
|
||||
public function registerEvents(): array
|
||||
{
|
||||
return [
|
||||
AfterSheet::Class => function (AfterSheet $event) {
|
||||
$count = count($this->data);
|
||||
foreach ($this->typeLists AS $cell => $typeList) {
|
||||
if ($cell && $typeList) {
|
||||
$p = $this->headings ? 1 : 0;
|
||||
for ($i = 1 + $p; $i <= max($count, $this->typeNumber) + $p; $i++) {
|
||||
$validation = $event->sheet->getDelegate()->getCell($cell . $i)->getDataValidation();
|
||||
$validation->setType(DataValidation::TYPE_LIST);
|
||||
$validation->setErrorStyle(DataValidation::STYLE_WARNING);
|
||||
$validation->setAllowBlank(false);
|
||||
$validation->setShowDropDown(true);
|
||||
$validation->setShowInputMessage(true);
|
||||
$validation->setShowErrorMessage(true);
|
||||
$validation->setErrorTitle('输入的值不合法');
|
||||
$validation->setError('选择的值不在列表中,请选择列表中的值');
|
||||
$validation->setPromptTitle('从列表中选择');
|
||||
$validation->setPrompt('请选择下拉列表中的值');
|
||||
$validation->setFormula1('"' . implode(',', $typeList) . '"');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Module;
|
||||
|
||||
|
||||
use Maatwebsite\Excel\Concerns\ToArray;
|
||||
|
||||
class BillImport implements ToArray
|
||||
{
|
||||
public function Array(Array $tables)
|
||||
{
|
||||
return $tables;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,14 +23,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
\Illuminate\Database\Query\Builder::macro('rawSql', function(){
|
||||
return array_reduce($this->getBindings(), function($sql, $binding){
|
||||
return preg_replace('/\?/', is_numeric($binding) ? $binding : "'".$binding."'" , $sql, 1);
|
||||
}, $this->toSql());
|
||||
});
|
||||
|
||||
\Illuminate\Database\Eloquent\Builder::macro('rawSql', function(){
|
||||
return ($this->getQuery()->rawSql());
|
||||
});
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,11 +127,9 @@ class WebSocketService implements WebSocketHandlerInterface
|
||||
case 'readMsg':
|
||||
$ids = is_array($data['id']) ? $data['id'] : [$data['id']];
|
||||
$userid = $this->getUserid($frame->fd);
|
||||
WebSocketDialogMsg::whereIn('id', $ids)->chunkById(20, function($list) use ($userid) {
|
||||
/** @var WebSocketDialogMsg $item */
|
||||
foreach ($list as $item) {
|
||||
$item->readSuccess($userid);
|
||||
}
|
||||
$list = WebSocketDialogMsg::whereIn('id', $ids)->get();
|
||||
$list->transform(function(WebSocketDialogMsg $item) use ($userid) {
|
||||
$item->readSuccess($userid);
|
||||
});
|
||||
return;
|
||||
|
||||
@@ -145,10 +143,10 @@ class WebSocketService implements WebSocketHandlerInterface
|
||||
$pathOld = $row->path;
|
||||
$row->path = $pathNew;
|
||||
$row->save();
|
||||
if (preg_match("/^\/single\/file\/\d+$/", $pathOld)) {
|
||||
if (preg_match("/^file\/content\/\d+$/", $pathOld)) {
|
||||
$this->pushPath($pathOld);
|
||||
}
|
||||
if (preg_match("/^\/single\/file\/\d+$/", $pathNew)) {
|
||||
if (preg_match("/^file\/content\/\d+$/", $pathNew)) {
|
||||
$this->pushPath($pathNew);
|
||||
}
|
||||
}
|
||||
@@ -206,19 +204,7 @@ class WebSocketService implements WebSocketHandlerInterface
|
||||
*/
|
||||
private function deleteUser($fd)
|
||||
{
|
||||
$array = [];
|
||||
WebSocket::whereFd($fd)->chunk(10, function($list) use (&$array) {
|
||||
/** @var WebSocket $item */
|
||||
foreach ($list as $item) {
|
||||
$item->delete();
|
||||
if ($item->path && str_starts_with($item->path, "/single/file/")) {
|
||||
$array[$item->path] = $item->path;
|
||||
}
|
||||
}
|
||||
});
|
||||
foreach ($array as $path) {
|
||||
$this->pushPath($path);
|
||||
}
|
||||
WebSocket::whereFd($fd)->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
namespace App\Tasks;
|
||||
|
||||
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
|
||||
|
||||
use App\Models\AbstractModel;
|
||||
use App\Models\ProjectTask;
|
||||
use App\Module\Base;
|
||||
use Carbon\Carbon;
|
||||
|
||||
/**
|
||||
* 完成的任务自动归档
|
||||
* Class AutoArchivedTask
|
||||
* @package App\Tasks
|
||||
*/
|
||||
class AutoArchivedTask extends AbstractTask
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$setting = Base::setting('system');
|
||||
if ($setting['auto_archived'] === 'open') {
|
||||
$archivedDay = floatval($setting['archived_day']);
|
||||
if ($archivedDay > 0) {
|
||||
$archivedDay = min(100, $archivedDay);
|
||||
$archivedTime = Carbon::now()->subDays($archivedDay);
|
||||
//获取已完成未归档的任务
|
||||
$taskLists = ProjectTask::whereNotNull('complete_at')
|
||||
->where('complete_at', '<=', $archivedTime)
|
||||
->where('archived_userid', 0)
|
||||
->whereNull('archived_at')
|
||||
->take(100)
|
||||
->get();
|
||||
foreach ($taskLists AS $task) {
|
||||
$task->archivedTask(Carbon::now(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tasks;
|
||||
|
||||
use App\Models\ProjectTask;
|
||||
use App\Models\ProjectTaskMailLog;
|
||||
use App\Models\User;
|
||||
use App\Module\Base;
|
||||
use Carbon\Carbon;
|
||||
use Guanguans\Notify\Factory;
|
||||
use Guanguans\Notify\Messages\EmailMessage;
|
||||
|
||||
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
|
||||
|
||||
class OverdueRemindEmailTask extends AbstractTask
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function start()
|
||||
{
|
||||
$setting = Base::setting('emailSetting');
|
||||
if ($setting['notice'] === 'open') {
|
||||
$hours = floatval($setting['task_remind_hours']);
|
||||
$hours2 = floatval($setting['task_remind_hours2']);
|
||||
if ($hours > 0) {
|
||||
ProjectTask::whereNull('complete_at')
|
||||
->whereNull('archived_at')
|
||||
->whereBetween("end_at", [
|
||||
Carbon::now()->addMinutes($hours * 60),
|
||||
Carbon::now()->addMinutes($hours * 60 + 10)
|
||||
])->chunkById(100, function ($tasks) {
|
||||
/** @var ProjectTask $task */
|
||||
foreach ($tasks as $task) {
|
||||
$this->overdueBeforeAfterEmail($task, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
if ($hours2 > 0) {
|
||||
ProjectTask::whereNull('complete_at')
|
||||
->whereNull('archived_at')
|
||||
->whereBetween("end_at", [
|
||||
Carbon::now()->subMinutes($hours2 * 60 + 10),
|
||||
Carbon::now()->subMinutes($hours2 * 60)
|
||||
])->chunkById(100, function ($tasks) {
|
||||
/** @var ProjectTask $task */
|
||||
foreach ($tasks as $task) {
|
||||
$this->overdueBeforeAfterEmail($task, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 过期前、超期后提醒
|
||||
* @param ProjectTask $task
|
||||
* @param $isBefore
|
||||
* @return void
|
||||
*/
|
||||
private function overdueBeforeAfterEmail(ProjectTask $task, $isBefore)
|
||||
{
|
||||
$userids = $task->taskUser->where('owner', 1)->pluck('userid')->toArray();
|
||||
if (empty($userids)) {
|
||||
return;
|
||||
}
|
||||
$users = User::whereIn('userid', $userids)->get();
|
||||
if (empty($users)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$setting = Base::setting('emailSetting');
|
||||
$hours = floatval($setting['task_remind_hours']);
|
||||
$hours2 = floatval($setting['task_remind_hours2']);
|
||||
|
||||
/** @var User $user */
|
||||
foreach ($users as $user) {
|
||||
$data = [
|
||||
'type' => $isBefore ? 1 : 2,
|
||||
'userid' => $user->userid,
|
||||
'task_id' => $task->id,
|
||||
];
|
||||
$emailLog = ProjectTaskMailLog::where($data)->first();
|
||||
if ($emailLog) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
if (!Base::isEmail($user->email)) {
|
||||
throw new \Exception("User email '{$user->email}' address error");
|
||||
}
|
||||
if ($isBefore) {
|
||||
$subject = env('APP_NAME') . " 任务提醒";
|
||||
$content = "<p>{$user->nickname} 您好:</p><p>您有一个任务【{$task->name}】还有{$hours}小时即将超时,请及时处理。</p>";
|
||||
} else {
|
||||
$subject = env('APP_NAME') . " 任务过期提醒";
|
||||
$content = "<p>{$user->nickname} 您好:</p><p>您的任务【{$task->name}】已经超时{$hours2}小时,请及时处理。</p>";
|
||||
}
|
||||
Factory::mailer()
|
||||
->setDsn("smtp://{$setting['account']}:{$setting['password']}@{$setting['smtp_server']}:{$setting['port']}?verify_peer=0")
|
||||
->setMessage(EmailMessage::create()
|
||||
->from(env('APP_NAME', 'Task') . " <{$setting['account']}>")
|
||||
->to($user->email)
|
||||
->subject($subject)
|
||||
->html($content))
|
||||
->send();
|
||||
$data['is_send'] = 1;
|
||||
} catch (\Exception $e) {
|
||||
$data['send_error'] = $e->getMessage();
|
||||
}
|
||||
$data['email'] = $user->email;
|
||||
ProjectTaskMailLog::createInstance($data)->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,11 +33,6 @@ class WebSocketDialogMsgTask extends AbstractTask
|
||||
|
||||
public function start()
|
||||
{
|
||||
global $_A;
|
||||
$_A = [
|
||||
'__fill_url_remote_url' => true,
|
||||
];
|
||||
//
|
||||
$msg = WebSocketDialogMsg::find($this->id);
|
||||
if (empty($msg)) {
|
||||
return;
|
||||
@@ -48,38 +43,30 @@ class WebSocketDialogMsgTask extends AbstractTask
|
||||
}
|
||||
|
||||
// 推送目标①:群成员
|
||||
$array = [];
|
||||
$userids = $dialog->dialogUser->pluck('userid')->toArray();
|
||||
foreach ($userids AS $userid) {
|
||||
if ($userid == $msg->userid) {
|
||||
continue;
|
||||
}
|
||||
$mention = preg_match("/<span class=\"mention user\" data-id=\"[0|{$userid}]\">/", $msg->type === 'text' ? $msg->msg['text'] : '');
|
||||
WebSocketDialogMsgRead::createInstance([
|
||||
'dialog_id' => $msg->dialog_id,
|
||||
'msg_id' => $msg->id,
|
||||
'userid' => $userid,
|
||||
'mention' => $mention,
|
||||
])->saveOrIgnore();
|
||||
$array[$userid] = $mention;
|
||||
}
|
||||
// 更新已发送数量
|
||||
$msg->send = WebSocketDialogMsgRead::whereMsgId($msg->id)->count();
|
||||
$msg->save();
|
||||
// 开始推送消息
|
||||
foreach ($array as $userid => $mention) {
|
||||
PushTask::push([
|
||||
'userid' => $userid,
|
||||
'ignoreFd' => $this->ignoreFd,
|
||||
'msg' => [
|
||||
'type' => 'dialog',
|
||||
'mode' => 'add',
|
||||
'data' => array_merge($msg->toArray(), [
|
||||
'mention' => $mention,
|
||||
]),
|
||||
]
|
||||
]);
|
||||
}
|
||||
PushTask::push([
|
||||
'userid' => $userids,
|
||||
'ignoreFd' => $this->ignoreFd,
|
||||
'msg' => [
|
||||
'type' => 'dialog',
|
||||
'mode' => 'add',
|
||||
'data' => $msg->toArray(),
|
||||
]
|
||||
]);
|
||||
|
||||
// 推送目标②:正在打开这个任务会话的会员
|
||||
if ($dialog->type == 'group' && $dialog->group_type == 'task') {
|
||||
|
||||
60
cliff.toml
60
cliff.toml
@@ -1,60 +0,0 @@
|
||||
# configuration file for git-cliff (0.1.0)
|
||||
|
||||
[changelog]
|
||||
# changelog header
|
||||
header = """
|
||||
# Changelog\n
|
||||
All notable changes to this project will be documented in this file.\n
|
||||
"""
|
||||
# template for the changelog body
|
||||
# https://tera.netlify.app/docs/#introduction
|
||||
body = """
|
||||
{% if version %}\
|
||||
## [{{ version | trim_start_matches(pat="v") }}]
|
||||
{% else %}\
|
||||
## [Unreleased]
|
||||
{% endif %}\
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
### {{ group | upper_first }}
|
||||
{% for commit in commits %}
|
||||
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\
|
||||
{% endfor %}
|
||||
{% endfor %}\n
|
||||
"""
|
||||
# remove the leading and trailing whitespace from the template
|
||||
trim = true
|
||||
# changelog footer
|
||||
footer = """
|
||||
"""
|
||||
|
||||
[git]
|
||||
# parse the commits based on https://www.conventionalcommits.org
|
||||
conventional_commits = true
|
||||
# filter out the commits that are not conventional
|
||||
filter_unconventional = true
|
||||
# regex for parsing and grouping commits
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "Features"},
|
||||
{ message = "^fix", group = "Bug Fixes"},
|
||||
{ message = "^doc", group = "Documentation"},
|
||||
{ message = "^perf", group = "Performance"},
|
||||
{ message = "^pref", group = "Performance"},
|
||||
{ message = "^refactor", group = "Refactor"},
|
||||
{ message = "^style", group = "Styling"},
|
||||
{ message = "^test", group = "Testing"},
|
||||
{ message = "^chore\\(release\\): prepare for", skip = true},
|
||||
{ message = "^chore", group = "Miscellaneous Tasks"},
|
||||
{ body = ".*security", group = "Security"},
|
||||
]
|
||||
# filter out the commits that are not matched by commit parsers
|
||||
filter_commits = true
|
||||
# glob pattern for matching git tags
|
||||
tag_pattern = "v[0-9]*"
|
||||
# regex for skipping tags
|
||||
skip_tags = "v0.1.0-beta.1"
|
||||
# regex for ignoring tags
|
||||
ignore_tags = ""
|
||||
# sort the tags chronologically
|
||||
date_order = false
|
||||
# sort the commits inside sections by oldest/newest order
|
||||
sort_commits = "oldest"
|
||||
189
cmd
189
cmd
@@ -12,8 +12,6 @@ OK="${Green}[OK]${Font}"
|
||||
Error="${Red}[错误]${Font}"
|
||||
|
||||
cur_path="$(pwd)"
|
||||
cur_arg=$@
|
||||
COMPOSE="docker-compose"
|
||||
|
||||
judge() {
|
||||
if [[ 0 -eq $? ]]; then
|
||||
@@ -32,15 +30,6 @@ rand() {
|
||||
echo $(($num%$max+$min))
|
||||
}
|
||||
|
||||
rand_string() {
|
||||
local lan=$1
|
||||
if [[ `uname` == 'Linux' ]]; then
|
||||
echo "$(date +%s%N | md5sum | cut -c 1-${lan})"
|
||||
else
|
||||
echo "$(docker run -it --rm alpine sh -c "date +%s%N | md5sum | cut -c 1-${lan}")"
|
||||
fi
|
||||
}
|
||||
|
||||
supervisorctl_restart() {
|
||||
local RES=`run_exec php "supervisorctl update $1"`
|
||||
if [ -z "$RES" ]; then
|
||||
@@ -56,24 +45,15 @@ check_docker() {
|
||||
echo -e "${Error} ${RedBG} 未安装 Docker!${Font}"
|
||||
exit 1
|
||||
fi
|
||||
docker-compose version &> /dev/null
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
COMPOSE="docker compose"
|
||||
fi
|
||||
if [[ -n `$COMPOSE version | grep -E "\sv*1"` ]]; then
|
||||
$COMPOSE version
|
||||
echo -e "${Error} ${RedBG} Docker-compose 版本过低,请升级至v2+!${Font}"
|
||||
echo -e "${Error} ${RedBG} 未安装 Docker-compose!${Font}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_node() {
|
||||
npm --version &> /dev/null
|
||||
npm --version > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${Error} ${RedBG} 未安装nodejs!${Font}"
|
||||
exit 1
|
||||
@@ -81,11 +61,12 @@ check_node() {
|
||||
}
|
||||
|
||||
docker_name() {
|
||||
echo `$COMPOSE ps | awk '{print $1}' | grep "\-$1\-"`
|
||||
echo `docker-compose ps | awk '{print $1}' | grep "\-$1\-"`
|
||||
}
|
||||
|
||||
run_compile() {
|
||||
local type=$1
|
||||
local npxcmd=""
|
||||
check_node
|
||||
if [ ! -d "./node_modules" ]; then
|
||||
npm install
|
||||
@@ -93,43 +74,29 @@ run_compile() {
|
||||
run_exec php "php bin/run --mode=$type"
|
||||
supervisorctl_restart php
|
||||
#
|
||||
mix -V &> /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
npxcmd="npx"
|
||||
fi
|
||||
if [ "$type" = "prod" ]; then
|
||||
rm -rf "./public/js/build"
|
||||
npx mix --production
|
||||
echo "$(rand_string 16)" > ./public/js/hash
|
||||
$npxcmd mix --production
|
||||
else
|
||||
npx mix watch --hot
|
||||
$npxcmd mix watch --hot
|
||||
fi
|
||||
}
|
||||
|
||||
run_electron() {
|
||||
local argv=$@
|
||||
check_node
|
||||
if [ ! -d "./node_modules" ]; then
|
||||
npm install
|
||||
fi
|
||||
if [ ! -d "./electron/node_modules" ]; then
|
||||
pushd electron
|
||||
npm install
|
||||
popd
|
||||
fi
|
||||
#
|
||||
if [ -d "./electron/dist" ]; then
|
||||
rm -rf "./electron/dist"
|
||||
fi
|
||||
if [ -d "./electron/public" ] && [ "$argv" != "--nobuild" ]; then
|
||||
rm -rf "./electron/public"
|
||||
fi
|
||||
mkdir -p ./electron/public
|
||||
cp ./electron/index.html ./electron/public/index.html
|
||||
#
|
||||
if [ "$argv" != "dev" ] && [ "$argv" != "--nobuild" ]; then
|
||||
npx mix --production -- --env --electron
|
||||
fi
|
||||
if [ "$argv" == "dev" ]; then
|
||||
run_exec php "php bin/run --mode=$argv"
|
||||
supervisorctl_restart php
|
||||
fi
|
||||
node ./electron/build.js $argv
|
||||
}
|
||||
|
||||
@@ -141,7 +108,11 @@ run_exec() {
|
||||
echo -e "${Error} ${RedBG} 没有找到 $container 容器! ${Font}"
|
||||
exit 1
|
||||
fi
|
||||
docker exec -it "$name" /bin/sh -c "$cmd"
|
||||
if [ "$container" = "mariadb" ] || [ "$container" = "nginx" ] || [ "$container" = "redis" ]; then
|
||||
docker exec -it "$name" /bin/sh -c "$cmd"
|
||||
else
|
||||
docker exec -it "$name" /bin/bash -c "$cmd"
|
||||
fi
|
||||
}
|
||||
|
||||
run_mysql() {
|
||||
@@ -180,7 +151,6 @@ run_mysql() {
|
||||
fi
|
||||
docker cp $filename $container_name:/
|
||||
run_exec mariadb "gunzip < /$inputname | mysql -u$username -p$password $database"
|
||||
run_exec php "php artisan migrate"
|
||||
judge "还原数据库"
|
||||
fi
|
||||
}
|
||||
@@ -198,11 +168,8 @@ env_set() {
|
||||
if [ -z "$exist" ]; then
|
||||
echo "$key=$val" >> $cur_path/.env
|
||||
else
|
||||
if [[ `uname` == 'Linux' ]]; then
|
||||
sed -i "/^${key}=/c\\${key}=${val}" ${cur_path}/.env
|
||||
else
|
||||
docker run -it --rm -v ${cur_path}:/www alpine sh -c "sed -i "/^${key}=/c\\${key}=${val}" /www/.env"
|
||||
fi
|
||||
command="sed -i '/^$key=/c\\$key=$val' /www/.env"
|
||||
docker run -it --rm -v ${cur_path}:/www alpine sh -c "$command"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${Error} ${RedBG} 设置env参数失败!${Font}"
|
||||
exit 1
|
||||
@@ -215,43 +182,16 @@ env_init() {
|
||||
cp .env.docker .env
|
||||
fi
|
||||
if [ -z "$(env_get DB_ROOT_PASSWORD)" ]; then
|
||||
env_set DB_ROOT_PASSWORD "$(rand_string 16)"
|
||||
env_set DB_ROOT_PASSWORD "$(docker run -it --rm alpine sh -c "date +%s%N | md5sum | cut -c 1-16")"
|
||||
fi
|
||||
if [ -z "$(env_get APP_ID)" ]; then
|
||||
env_set APP_ID "$(rand_string 6)"
|
||||
env_set APP_ID "$(docker run -it --rm alpine sh -c "date +%s%N | md5sum | cut -c 1-6")"
|
||||
fi
|
||||
if [ -z "$(env_get APP_IPPR)" ]; then
|
||||
env_set APP_IPPR "10.$(rand 50 100).$(rand 100 200)"
|
||||
fi
|
||||
}
|
||||
|
||||
arg_get() {
|
||||
local find="n"
|
||||
local value=""
|
||||
for var in $cur_arg; do
|
||||
if [[ "$find" == "y" ]]; then
|
||||
if [[ ! $var =~ "--" ]]; then
|
||||
value=$var
|
||||
fi
|
||||
break
|
||||
fi
|
||||
if [[ "--$1" == "$var" ]] || [[ "-$1" == "$var" ]]; then
|
||||
find="y"
|
||||
value="yes"
|
||||
fi
|
||||
done
|
||||
echo $value
|
||||
}
|
||||
|
||||
is_arm() {
|
||||
local get_arch=`arch`
|
||||
if [[ $get_arch =~ "aarch" ]] || [[ $get_arch =~ "arm" ]]; then
|
||||
echo "yes"
|
||||
else
|
||||
echo "no"
|
||||
fi
|
||||
}
|
||||
|
||||
####################################################################################
|
||||
####################################################################################
|
||||
####################################################################################
|
||||
@@ -264,71 +204,31 @@ fi
|
||||
if [ $# -gt 0 ]; then
|
||||
if [[ "$1" == "init" ]] || [[ "$1" == "install" ]]; then
|
||||
shift 1
|
||||
# 判断架构
|
||||
if [[ "$(is_arm)" == "yes" ]] && [[ -z "$(arg_get force)" ]]; then
|
||||
echo -e "${Error} ${RedBG}暂不支持arm架构,强制安装请使用:./cmd install --force${Font}"
|
||||
exit 1
|
||||
fi
|
||||
# 初始化文件
|
||||
if [[ -n "$(arg_get relock)" ]]; then
|
||||
rm -rf node_modules
|
||||
rm -rf package-lock.json
|
||||
rm -rf vendor
|
||||
rm -rf composer.lock
|
||||
fi
|
||||
mkdir -p "${cur_path}/docker/log/supervisor"
|
||||
mkdir -p "${cur_path}/docker/mysql/data"
|
||||
chmod -R 775 "${cur_path}/docker/log/supervisor"
|
||||
chmod -R 775 "${cur_path}/docker/mysql/data"
|
||||
# 启动容器
|
||||
[[ "$(arg_get port)" -gt 0 ]] && env_set APP_PORT "$(arg_get port)"
|
||||
$COMPOSE up php -d
|
||||
# 安装composer依赖
|
||||
rm -rf composer.lock
|
||||
rm -rf package-lock.json
|
||||
mkdir -p ${cur_path}/docker/mysql/data
|
||||
chmod -R 777 ${cur_path}/docker/mysql/data
|
||||
docker-compose up -d
|
||||
docker-compose restart php
|
||||
run_exec php "composer install"
|
||||
if [ ! -f "${cur_path}/vendor/autoload.php" ]; then
|
||||
run_exec php "composer config repo.packagist composer https://packagist.phpcomposer.com"
|
||||
run_exec php "composer install"
|
||||
run_exec php "composer config --unset repos.packagist"
|
||||
fi
|
||||
if [ ! -f "${cur_path}/vendor/autoload.php" ]; then
|
||||
echo -e "${Error} ${RedBG}composer install 失败,请重试! ${Font}"
|
||||
exit 1
|
||||
fi
|
||||
[[ -z "$(env_get APP_KEY)" ]] && run_exec php "php artisan key:generate"
|
||||
run_exec php "php bin/run --mode=prod"
|
||||
# 检查数据库
|
||||
remaining=20
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
chmod -R 775 "${cur_path}/docker/mysql/data"
|
||||
sleep 3
|
||||
done
|
||||
[ -z "$(env_get APP_KEY)" ] && run_exec php "php artisan key:generate"
|
||||
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}"
|
||||
exit 1
|
||||
fi
|
||||
# 设置初始化密码
|
||||
run_exec php "php bin/run --mode=prod"
|
||||
res=`run_exec mariadb "sh /etc/mysql/repassword.sh"`
|
||||
$COMPOSE up -d
|
||||
supervisorctl_restart php
|
||||
docker-compose stop
|
||||
docker-compose start
|
||||
echo -e "${OK} ${GreenBG} 安装完成 ${Font}"
|
||||
echo -e "地址: http://${GreenBG}127.0.0.1:$(env_get APP_PORT)${Font}"
|
||||
echo -e "$res"
|
||||
elif [[ "$1" == "update" ]]; then
|
||||
shift 1
|
||||
run_mysql backup
|
||||
git fetch --all
|
||||
git reset --hard origin/$(git branch | sed -n -e 's/^\* \(.*\)/\1/p')
|
||||
git pull
|
||||
run_exec php "composer update"
|
||||
run_exec php "php artisan migrate"
|
||||
supervisorctl_restart php
|
||||
$COMPOSE up -d
|
||||
docker-compose up -d
|
||||
elif [[ "$1" == "uninstall" ]]; then
|
||||
shift 1
|
||||
read -rp "确定要卸载(含:删除容器、数据库、日志)吗?(y/n): " uninstall
|
||||
@@ -342,22 +242,11 @@ if [ $# -gt 0 ]; then
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
$COMPOSE down
|
||||
docker-compose down
|
||||
rm -rf "./docker/mysql/data"
|
||||
rm -rf "./docker/log/supervisor"
|
||||
find "./storage/logs" -name "*.log" | xargs rm -rf
|
||||
echo -e "${OK} ${GreenBG} 卸载完成 ${Font}"
|
||||
elif [[ "$1" == "reinstall" ]]; then
|
||||
shift 1
|
||||
./cmd uninstall $@
|
||||
sleep 3
|
||||
./cmd install $@
|
||||
elif [[ "$1" == "port" ]]; 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}"
|
||||
elif [[ "$1" == "repassword" ]]; then
|
||||
shift 1
|
||||
run_exec mariadb "sh /etc/mysql/repassword.sh \"$@\""
|
||||
@@ -414,10 +303,10 @@ if [ $# -gt 0 ]; then
|
||||
elif [[ "$1" == "composer" ]]; then
|
||||
shift 1
|
||||
e="composer $@" && run_exec php "$e"
|
||||
elif [[ "$1" == "service" ]]; then
|
||||
elif [[ "$1" == "super" ]]; then
|
||||
shift 1
|
||||
e="service $@" && run_exec php "$e"
|
||||
elif [[ "$1" == "super" ]] || [[ "$1" == "supervisorctl" ]]; then
|
||||
supervisorctl_restart "$@"
|
||||
elif [[ "$1" == "supervisorctl" ]]; then
|
||||
shift 1
|
||||
e="supervisorctl $@" && run_exec php "$e"
|
||||
elif [[ "$1" == "models" ]]; then
|
||||
@@ -428,11 +317,11 @@ if [ $# -gt 0 ]; then
|
||||
e="./vendor/bin/phpunit $@" && run_exec php "$e"
|
||||
elif [[ "$1" == "restart" ]]; then
|
||||
shift 1
|
||||
$COMPOSE stop "$@"
|
||||
$COMPOSE start "$@"
|
||||
docker-compose stop "$@"
|
||||
docker-compose start "$@"
|
||||
else
|
||||
$COMPOSE "$@"
|
||||
docker-compose "$@"
|
||||
fi
|
||||
else
|
||||
$COMPOSE ps
|
||||
docker-compose ps
|
||||
fi
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
"ext-simplexml": "*",
|
||||
"fideloper/proxy": "^4.4.1",
|
||||
"fruitcake/laravel-cors": "^2.0.4",
|
||||
"guanguans/notify": "^1.20",
|
||||
"guzzlehttp/guzzle": "^7.3.0",
|
||||
"laravel/framework": "^v8.48.1",
|
||||
"laravel/tinker": "^v2.6.1",
|
||||
|
||||
9928
composer.lock
generated
9928
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -300,9 +300,9 @@ return [
|
||||
'log_level' => 4,
|
||||
'log_file' => storage_path(sprintf('logs/swoole-%s.log', date('Y-m'))),
|
||||
'document_root' => base_path('public'),
|
||||
'buffer_output_size' => 512 * 1024 * 1024,
|
||||
'socket_buffer_size' => 512 * 1024 * 1024,
|
||||
'package_max_length' => 512 * 1024 * 1024,
|
||||
'buffer_output_size' => 200 * 1024 * 1024,
|
||||
'socket_buffer_size' => 256 * 1024 * 1024,
|
||||
'package_max_length' => 200 * 1024 * 1024,
|
||||
'reload_async' => true,
|
||||
'max_wait_time' => 60,
|
||||
'enable_reuse_port' => true,
|
||||
|
||||
@@ -17,7 +17,7 @@ class CreateProjectLogsTable extends Migration
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('project_id')->nullable()->default(0)->comment('项目ID');
|
||||
$table->bigInteger('column_id')->nullable()->default(0)->comment('列表ID');
|
||||
$table->bigInteger('task_id')->nullable()->default(0)->comment('任务ID');
|
||||
$table->bigInteger('task_id')->nullable()->default(0)->comment('项目ID');
|
||||
$table->bigInteger('userid')->nullable()->default(0)->comment('会员ID');
|
||||
$table->string('detail', 500)->nullable()->default('')->comment('详细信息');
|
||||
$table->timestamps();
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateProjectInvitesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('project_invites', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('project_id')->nullable()->default(0)->comment('项目ID');
|
||||
$table->integer('num')->nullable()->default(0)->comment('累计邀请');
|
||||
$table->string('code')->nullable()->default('')->comment('链接码');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('project_invites');
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateFileLinksTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('file_links', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('file_id')->nullable()->default(0)->comment('文件ID');
|
||||
$table->integer('num')->nullable()->default(0)->comment('累计访问');
|
||||
$table->string('code')->nullable()->default('')->comment('链接码');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('file_links');
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\File;
|
||||
use App\Models\FileUser;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class FileUsersAddPermission extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$isAdd = false;
|
||||
Schema::table('file_users', function (Blueprint $table) use (&$isAdd) {
|
||||
if (!Schema::hasColumn('file_users', 'permission')) {
|
||||
$isAdd = true;
|
||||
$table->tinyInteger('permission')->nullable()->default(0)->after('userid')->comment('权限:0只读,1读写');
|
||||
}
|
||||
});
|
||||
if ($isAdd) {
|
||||
// 更新数据
|
||||
File::whereShare(1)->chunkById(100, function ($lists) {
|
||||
foreach ($lists as $file) {
|
||||
FileUser::updateInsert([
|
||||
'file_id' => $file->id,
|
||||
'userid' => 0,
|
||||
]);
|
||||
}
|
||||
});
|
||||
File::whereShare(2)->update([
|
||||
'share' => 1,
|
||||
]);
|
||||
FileUser::wherePermission(0)->update([
|
||||
'permission' => 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('file_users', function (Blueprint $table) {
|
||||
$table->dropColumn("permission");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateReportsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if ( Schema::hasTable('reports') )
|
||||
return;
|
||||
|
||||
Schema::create('reports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->timestamps();
|
||||
$table->string("title")->default("")->comment("标题");
|
||||
$table->enum("type", ["weekly", "daily"])->default("daily")->comment("汇报类型");
|
||||
$table->unsignedBigInteger("userid")->default(0);
|
||||
$table->longText("content")->nullable();
|
||||
$table->index(["userid", "created_at"], "default");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('reports');
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateReportReceivesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
if ( Schema::hasTable('report_receives') )
|
||||
return;
|
||||
|
||||
Schema::create('report_receives', function (Blueprint $table) {
|
||||
$table->bigIncrements("id");
|
||||
$table->unsignedInteger("rid")->default(0);
|
||||
$table->timestamp("receive_time")->nullable()->comment("接收时间");
|
||||
$table->unsignedBigInteger("userid")->default(0)->comment("接收人");
|
||||
$table->unsignedTinyInteger("read")->default(0)->comment("是否已读");
|
||||
$table->index(["userid", "receive_time"], "default");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('report_receives');
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddReportSign extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('reports', function (Blueprint $table) {
|
||||
$table->string("sign")->default("")->comment("汇报唯一标识");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('reports', function (Blueprint $table) {
|
||||
$table->dropColumn("sign");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class UsersAddDisableAt extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$isAdd = false;
|
||||
Schema::table('users', function (Blueprint $table) use (&$isAdd) {
|
||||
if (!Schema::hasColumn('users', 'disable_at')) {
|
||||
$isAdd = true;
|
||||
$table->timestamp('disable_at')->nullable()->after('created_ip')->comment('禁用时间');
|
||||
}
|
||||
});
|
||||
if ($isAdd) {
|
||||
User::where("identity", "like", "%,disable,%")->update([
|
||||
'disable_at' => Carbon::now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn("disable_at");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\ProjectTask;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class ProjectTasksUpdateSubtaskTime extends Migration
|
||||
{
|
||||
/**
|
||||
* 子任务同步主任务(任务时间)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
ProjectTask::where('parent_id', '>', 0)
|
||||
->whereNull('end_at')
|
||||
->chunkById(100, function ($lists) {
|
||||
/** @var ProjectTask $task */
|
||||
foreach ($lists as $task) {
|
||||
$parent = ProjectTask::whereNotNull('end_at')->find($task->parent_id);
|
||||
if ($parent) {
|
||||
$task->start_at = $parent->start_at;
|
||||
$task->end_at = $parent->end_at;
|
||||
$task->save();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\ProjectTask;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class ProjectTasksUpdateSubtaskArchivedDelete extends Migration
|
||||
{
|
||||
/**
|
||||
* 子任务同步主任务(归档、删除)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// 归档
|
||||
ProjectTask::whereParentId(0)
|
||||
->whereNotNull('archived_at')
|
||||
->chunkById(100, function ($lists) {
|
||||
/** @var ProjectTask $task */
|
||||
foreach ($lists as $task) {
|
||||
ProjectTask::whereParentId($task->id)->update([
|
||||
'archived_at' => $task->archived_at,
|
||||
'archived_userid' => $task->archived_userid,
|
||||
'archived_follow' => $task->archived_follow,
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
// 删除
|
||||
ProjectTask::onlyTrashed()
|
||||
->whereParentId(0)
|
||||
->chunkById(100, function ($lists) {
|
||||
/** @var ProjectTask $task */
|
||||
foreach ($lists as $task) {
|
||||
ProjectTask::whereParentId($task->id)->update([
|
||||
'deleted_at' => $task->deleted_at,
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateProjectFlowItemsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('project_flow_items', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('project_id')->nullable()->default(0)->comment('项目ID');
|
||||
$table->bigInteger('flow_id')->nullable()->default(0)->comment('流程ID');
|
||||
$table->string('name', 50)->nullable()->default('')->comment('名称');
|
||||
$table->string('status', 20)->nullable()->default('')->comment('状态');
|
||||
$table->string('turns')->nullable()->default('')->comment('可流转');
|
||||
$table->string('userids')->nullable()->default('')->comment('状态负责人ID');
|
||||
$table->integer('sort')->nullable()->comment('排序');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('project_flow_items');
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateProjectFlowsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('project_flows', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('project_id')->nullable()->default(0)->comment('项目ID');
|
||||
$table->string('name', 50)->nullable()->default('')->comment('流程名称');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('project_flows');
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ProjectTasksAddFlowItemIdFlowItemName extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('project_tasks', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('project_tasks', 'flow_item_id')) {
|
||||
$table->bigInteger('flow_item_id')->nullable()->default(0)->after('dialog_id')->comment('工作流状态ID');
|
||||
$table->string('flow_item_name', 50)->nullable()->default('')->after('flow_item_id')->comment('工作流状态名称');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('project_tasks', function (Blueprint $table) {
|
||||
$table->dropColumn("flow_item_id");
|
||||
$table->dropColumn("flow_item_name");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\ProjectFlowItem;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ProjectFlowItemsAddUsertype extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$isAdd = false;
|
||||
Schema::table('project_flow_items', function (Blueprint $table) use (&$isAdd) {
|
||||
if (!Schema::hasColumn('project_flow_items', 'usertype')) {
|
||||
$isAdd = true;
|
||||
$table->string('usertype', 10)->nullable()->default('')->after('userids')->comment('流转模式');
|
||||
}
|
||||
});
|
||||
if ($isAdd) {
|
||||
ProjectFlowItem::where("usertype", "")->update([
|
||||
'usertype' => 'add',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('project_flow_items', function (Blueprint $table) {
|
||||
$table->dropColumn("usertype");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ProjectLogsAddRecord extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('project_logs', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('project_logs', 'record')) {
|
||||
$table->text('record')->nullable()->after('detail')->comment('记录数据');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('project_logs', function (Blueprint $table) {
|
||||
$table->dropColumn("record");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ProjectFlowItemsAddUserlimit extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('project_flow_items', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('project_flow_items', 'userlimit')) {
|
||||
$table->tinyInteger('userlimit')->nullable()->default(0)->after('usertype')->comment('限制负责人');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('project_flow_items', function (Blueprint $table) {
|
||||
$table->dropColumn("userlimit");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class WebSocketDialogMsgsAddDeletes 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', 'deleted_at')) {
|
||||
$table->softDeletes();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_msgs', function (Blueprint $table) {
|
||||
$table->dropSoftDeletes();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class InsertSettingColumnTemplate extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$array = \App\Module\Base::setting('columnTemplate');
|
||||
if (empty($array)) {
|
||||
\App\Module\Base::setting('columnTemplate', [
|
||||
[
|
||||
'name' => '软件开发',
|
||||
'columns' => ['产品规划', '前端开发', '后端开发', '测试', '发布', '其他'],
|
||||
],
|
||||
[
|
||||
'name' => '产品开发',
|
||||
'columns' => ['产品计划', '正在设计', '正在研发', '测试', '准备发布', '发布成功'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class WebSocketDialogUsersAddTopAt 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', 'top_at')) {
|
||||
$table->timestamp('top_at')->nullable()->after('userid')->comment('置顶时间');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
|
||||
$table->dropColumn("top_at");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\File;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class FilesUpdateType extends Migration
|
||||
{
|
||||
/**
|
||||
* 更改流程图文件类型
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
File::whereType('flow')->update([
|
||||
'type' => 'drawio'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
File::whereType('drawio')->update([
|
||||
'type' => 'flow'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
|
||||
|
||||
use App\Models\File;
|
||||
use App\Models\FileContent;
|
||||
use App\Module\Base;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class FilesUpdateExt extends Migration
|
||||
{
|
||||
/**
|
||||
* 更新后缀
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
File::whereIn('type', ['mind', 'drawio', 'document'])->where('ext', '')->orderBy('id')->chunk(100, function($files) {
|
||||
/** @var File $file */
|
||||
foreach ($files as $file) {
|
||||
$fileContent = FileContent::whereFid($file->id)->orderByDesc('id')->first();
|
||||
$contentArray = Base::json2array($fileContent?->content);
|
||||
$contentString = '';
|
||||
//
|
||||
switch ($file->type) {
|
||||
case 'document':
|
||||
$file->ext = $contentArray['type'] ?: 'md';
|
||||
$contentString = $contentArray['content'];
|
||||
break;
|
||||
case 'drawio':
|
||||
$file->ext = 'drawio';
|
||||
$contentString = $contentArray['xml'];
|
||||
break;
|
||||
case 'mind':
|
||||
$file->ext = 'mind';
|
||||
$contentString = $fileContent?->content;
|
||||
break;
|
||||
}
|
||||
$file->save();
|
||||
//
|
||||
$path = 'uploads/file/' . $file->type . '/' . date("Ym", Carbon::parse($file->created_at)->timestamp) . '/' . $file->id . '/' . md5($contentString);
|
||||
$save = public_path($path);
|
||||
Base::makeDir(dirname($save));
|
||||
file_put_contents($save, $contentString);
|
||||
$content = [
|
||||
'type' => $file->ext,
|
||||
'url' => $path
|
||||
];
|
||||
//
|
||||
$content = FileContent::createInstance([
|
||||
'fid' => $file->id,
|
||||
'content' => $content,
|
||||
'text' => $fileContent?->text,
|
||||
'size' => $file->size,
|
||||
'userid' => $file->userid,
|
||||
]);
|
||||
$content->save();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
File::whereIn('ext', ['mind', 'drawio', 'md'])->update([
|
||||
'ext' => ''
|
||||
]);
|
||||
// ... 退回去意义不大,文件内容不做回滚操作
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class ProjectUsersAddTopAt extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('project_users', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('project_users', 'top_at')) {
|
||||
$table->timestamp('top_at')->nullable()->after('owner')->comment('置顶时间');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('project_users', function (Blueprint $table) {
|
||||
$table->dropColumn("top_at");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateProjectTaskFlowChangesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('project_task_flow_changes', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->bigInteger('task_id')->nullable()->default(0)->comment('任务ID');
|
||||
$table->bigInteger('userid')->nullable()->default(0)->comment('会员ID');
|
||||
$table->bigInteger('before_item_id')->nullable()->default(0)->comment('(变化前)工作流状态ID');
|
||||
$table->string('before_item_name', 50)->nullable()->default('')->comment('(变化前)工作流状态名称');
|
||||
$table->bigInteger('after_item_id')->nullable()->default(0)->comment('(变化后)工作流状态ID');
|
||||
$table->string('after_item_name', 50)->nullable()->default('')->comment('(变化后)工作流状态名称');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('project_task_flow_changes');
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class RenamePreProjectTaskFlowChangesItem extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('project_task_flow_changes', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('project_task_flow_changes', 'before_item_id')) {
|
||||
$table->renameColumn('before_item_id', 'before_flow_item_id');
|
||||
$table->renameColumn('before_item_name', 'before_flow_item_name');
|
||||
$table->renameColumn('after_item_id', 'after_flow_item_id');
|
||||
$table->renameColumn('after_item_name', 'after_flow_item_name');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('project_task_flow_changes', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddIsEmailVerityToUsers extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('users', 'is_email_verity')) {
|
||||
$table->boolean('is_email_verity')->default(0)->nullable()->after('disable_at')->comment('邮箱是否已验证');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn("is_email_verity");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateUserEmailVerificationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('user_email_verifications', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->bigInteger('userid')->nullable()->default(0)->comment('用户id');
|
||||
$table->string('code')->nullable()->default('')->comment('验证参数');
|
||||
$table->string('email')->nullable()->default('')->comment('电子邮箱');
|
||||
$table->integer('status')->nullable()->default(0)->comment('0-未验证,1-已验证');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('user_email_verifications');
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateProjectTaskMailLogsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('project_task_mail_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->bigInteger('userid')->nullable()->default(0)->comment('用户id');
|
||||
$table->integer('task_id')->nullable()->default(0)->comment('任务id');
|
||||
$table->string('email')->nullable()->default('')->comment('电子邮箱');
|
||||
$table->tinyInteger('type')->nullable()->default(0)->comment('提醒类型:1第一次任务提醒,2第二次任务超期提醒');
|
||||
$table->tinyInteger('is_send')->nullable()->default(0)->comment('邮件发送是否成功:0否,1是');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('project_task_mail_logs');
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
@error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING);
|
||||
|
||||
use App\Models\ProjectTaskContent;
|
||||
use App\Module\Base;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class ProjectTaskContentsUpdateContent extends Migration
|
||||
{
|
||||
/**
|
||||
* 任务详细描述保存至文件
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
ProjectTaskContent::orderBy('id')->chunk(100, function($items) {
|
||||
/** @var ProjectTaskContent $item */
|
||||
foreach ($items as $item) {
|
||||
$content = Base::json2array($item->content);
|
||||
if (!isset($content['url'])) {
|
||||
$item->content = Base::array2json([
|
||||
'url' => ProjectTaskContent::saveContent($item->task_id, $item->content)
|
||||
]);
|
||||
$item->save();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// ... 退回去意义不大,文件内容不做回滚操作
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddWebSocketDialogUsersAddIsMarkUnread 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', 'is_mark_unread')) {
|
||||
$table->boolean('is_mark_unread')->default(0)->nullable()->after('top_at')->comment('是否标记为未读:0否,1是');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
|
||||
$table->dropColumn("is_mark_unread");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddProjectTaskMailLogsAddDeletes extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('project_task_mail_logs', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('project_task_mail_logs', 'deleted_at')) {
|
||||
$table->softDeletes();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('project_task_mail_logs', function (Blueprint $table) {
|
||||
$table->dropSoftDeletes();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddProjectTasksDeletedUserid extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('project_tasks', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('project_tasks', 'deleted_userid')) {
|
||||
$table->bigInteger('deleted_userid')->nullable()->default(0)->after('deleted_at')->comment('删除会员');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('project_tasks', function (Blueprint $table) {
|
||||
$table->dropColumn("deleted_userid");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class RenamePreUsersIsEmailVerity extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$isAdd = false;
|
||||
Schema::table('users', function (Blueprint $table) use (&$isAdd) {
|
||||
if (Schema::hasColumn('users', 'is_email_verity')) {
|
||||
$isAdd = true;
|
||||
$table->renameColumn('is_email_verity', 'email_verity');
|
||||
}
|
||||
});
|
||||
if ($isAdd) {
|
||||
\App\Models\User::where("identity", "like", "%,admin,%")->chunkById(100, function ($lists) {
|
||||
foreach ($lists as $item) {
|
||||
if (!$item->email_verity) {
|
||||
$item->email_verity = 1;
|
||||
$item->save();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class RenamePreWebSocketDialogUsersIsMarkUnread 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', 'is_mark_unread')) {
|
||||
$table->renameColumn('is_mark_unread', 'mark_unread');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('web_socket_dialog_users', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddFilesPids extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$isAdd = false;
|
||||
Schema::table('files', function (Blueprint $table) use (&$isAdd) {
|
||||
if (!Schema::hasColumn('files', 'pids')) {
|
||||
$isAdd = true;
|
||||
$table->string('pids', 255)->nullable()->default('')->after('pid')->comment('上级ID递归');
|
||||
}
|
||||
});
|
||||
if ($isAdd) {
|
||||
// 更新数据
|
||||
\App\Models\File::where('pid', '>', 0)->chunkById(100, function ($lists) {
|
||||
/** @var \App\Models\File $item */
|
||||
foreach ($lists as $item) {
|
||||
$item->saveBeforePids();
|
||||
}
|
||||
});
|
||||
\App\Models\File::whereShare(0)->chunkById(100, function ($lists) {
|
||||
/** @var \App\Models\File $item */
|
||||
foreach ($lists as $item) {
|
||||
\App\Models\FileUser::whereFileId($item->id)->delete();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('files', function (Blueprint $table) {
|
||||
$table->dropColumn("pids");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddFileLinksUserid extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$isAdd = false;
|
||||
Schema::table('file_links', function (Blueprint $table) use (&$isAdd) {
|
||||
if (!Schema::hasColumn('file_links', 'userid')) {
|
||||
$isAdd = true;
|
||||
$table->bigInteger('userid')->nullable()->default(0)->after('code')->comment('会员ID');
|
||||
}
|
||||
});
|
||||
if ($isAdd) {
|
||||
// 更新数据
|
||||
\App\Models\FileLink::chunkById(100, function ($lists) {
|
||||
/** @var \App\Models\FileLink $item */
|
||||
foreach ($lists as $item) {
|
||||
$item->userid = intval(\App\Models\File::whereId($item->file_id)->value('userid'));
|
||||
$item->save();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('file_links', function (Blueprint $table) {
|
||||
$table->dropColumn("userid");
|
||||
});
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user