feat: 文件支持只读、读/写细化设置

This commit is contained in:
kuaifan 2021-12-29 08:38:45 +08:00
parent cef6646f50
commit 2b0467e00f
6 changed files with 213 additions and 132 deletions

View File

@ -35,12 +35,7 @@ class FileController extends AbstractController
$pid = intval($data['pid']);
//
if ($pid > 0) {
$file = File::find($pid);
if (empty($file)) {
return Base::retError('Not exist');
}
$file->exceAllow($user->userid);
//
File::allowFind($pid);
$builder = File::wherePid($pid);
} else {
$builder = File::whereUserid($user->userid);
@ -61,13 +56,11 @@ class FileController extends AbstractController
}
} else {
// 获取共享相关
$list = File::where('userid', '!=', $user->userid)->where(function ($query) use ($user) {
$query->where('share', 1)->orWhere(function ($q2) use ($user) {
$q2->where('share', 2)->whereIn('id', function ($q3) use ($user) {
$q3->select('file_id')->from('file_users')->where('userid', $user->userid);
});
});
})->get();
$list = File::select(['files.*', 'file_users.permission'])
->join('file_users', 'files.id', '=', 'file_users.file_id')
->where('files.userid', '!=', $user->userid)
->where('file_users.userid', $user->userid)
->get();
if ($list->isNotEmpty()) {
foreach ($list as $file) {
$temp = $file->toArray();
@ -512,34 +505,35 @@ class FileController extends AbstractController
return Base::retError('仅限所有者操作');
}
//
$userids = FileUser::whereFileId($file->id)->pluck('userid')->toArray();
$list = FileUser::whereFileId($file->id)->get();
//
return Base::retSuccess('success', [
'id' => $file->id,
'userids' => $userids
'list' => $list
]);
}
/**
* 获取共享信息
* 设置共享
*
* @apiParam {Number} id 文件ID
* @apiParam {String} action 动作
* - share: 设置共享
* - unshare: 取消共享
* @apiParam {Number} [share] 共享对象
* - 1: 共享给所有人(限管理员)
* - 2: 共享给指定成员
* @apiParam {Array} [userids] 共享成员,格式: [userid1, userid2, userid3]
* @apiParam {Number} [permission] 共享方式
* - 0:只读
* - 1:读写
* - -1: 删除
*/
public function share__update()
{
$user = User::auth();
//
$id = intval(Request::input('id'));
$action = Request::input('action');
$share = intval(Request::input('share'));
$userids = Request::input('userids');
$permission = intval(Request::input('permission'));
//
if (!in_array($permission, [-1, 0, 1])) {
return Base::retError('参数错误');
}
//
$file = File::whereId($id)->first();
if (empty($file)) {
@ -553,56 +547,45 @@ class FileController extends AbstractController
return Base::retError('已经处于共享文件夹中');
}
//
if ($action == 'unshare') {
// 取消共享
if ($file->share == 1) {
$uids = WebSocket::select(['userid'])->pluck('userid')->toArray();
} else {
$uids = FileUser::whereFileId($file->id)->pluck('userid')->toArray();
}
$uids = array_values(array_diff($uids, [$user->userid]));
//
$file->setShare(0);
$message = '取消成功';
} else {
// 设置共享
switch ($share) {
case 1:
$user->isAdmin();
break;
case 2:
$array = [];
if (is_array($userids)) {
foreach ($userids as $userid) {
if (!intval($userid)) continue;
if (!User::whereUserid($userid)->exists()) continue;
FileUser::updateInsert([
'file_id' => $file->id,
'userid' => $userid,
]);
$array[] = $userid;
}
}
if (empty($array)) {
return Base::retError('请选择共享成员');
}
$builder = FileUser::whereFileId($file->id)->whereNotIn('userid', $array);
$uids = (clone $builder)->pluck('userid')->toArray();
$builder->delete();
break;
default:
return Base::retError('请选择共享对象');
}
$file->setShare($share);
$message = '设置成功';
if (!is_array($userids) || empty($userids)) {
return Base::retError('请选择共享对象');
}
//
$file->pushMsg('update', $file);
if (isset($uids)) {
$file->pushMsg('delete', null, $uids);
$array = [];
if ($permission === -1) {
// 取消共享
$action = "delete";
foreach ($userids as $userid) {
if (!intval($userid)) continue;
if (FileUser::where([
'file_id' => $file->id,
'userid' => $userid,
])->delete()) {
$array[] = $userid;
}
}
} else {
// 设置共享
$action = "update";
if (FileUser::whereFileId($file->id)->count() + count($userids) > 100) {
return Base::retError('共享人数上限100个成员');
}
foreach ($userids as $userid) {
if (!intval($userid)) continue;
if (!User::whereUserid($userid)->exists()) continue;
if (FileUser::updateInsert([
'file_id' => $file->id,
'userid' => $userid,
], [
'permission' => $permission,
])) {
$array[] = $userid;
}
}
}
return Base::retSuccess($message, $file);
//
$file->setShare();
$file->pushMsg($action, $action == "delete" ? null : $file, $array);
return Base::retSuccess($action == "delete" ? "删除成功" : "设置成功", $file);
}
}

View File

@ -51,7 +51,7 @@ class File extends AbstractModel
use SoftDeletes;
/**
* 是否有访问权限(没有时抛出异常)
* 是否有访问权限
* @param $userid
*/
public function exceAllow($userid)
@ -64,8 +64,7 @@ class File extends AbstractModel
/**
* 是否有访问权限
* 自己的文件夹
* 共享所有人的文件夹
* 在指定共享人员内
* 在指定共享成员内
* @param $userid
* @return bool
*/
@ -77,14 +76,9 @@ class File extends AbstractModel
}
$row = $this->getShareInfo();
if ($row) {
if ($row->share == 1) {
// ② 共享所有人的文件夹
if (FileUser::whereFileId($row->id)->whereUserid($userid)->exists()) {
// ② 在指定共享成员内
return true;
} elseif ($row->share == 2) {
// ③ 在指定共享人员内
if (FileUser::whereFileId($row->id)->whereUserid($userid)->exists()) {
return true;
}
}
}
return false;
@ -96,7 +90,7 @@ class File extends AbstractModel
*/
public function getShareInfo()
{
if ($this->share > 0) {
if ($this->share) {
return $this;
}
$pid = $this->pid;
@ -105,7 +99,7 @@ class File extends AbstractModel
if (empty($row)) {
break;
}
if ($row->share > 0) {
if ($row->share) {
return $row;
}
$pid = $row->pid;
@ -125,7 +119,7 @@ class File extends AbstractModel
if (empty($row)) {
break;
}
if ($row->share > 0) {
if ($row->share) {
return true;
}
$pid = $row->pid;
@ -138,18 +132,23 @@ class File extends AbstractModel
* @param $share
* @return bool
*/
public function setShare($share)
public function setShare($share = null)
{
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);
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();
$list = self::wherePid($this->id)->get();
if ($list->isNotEmpty()) {
foreach ($list as $item) {
$item->setShare(0);
}
}
}
});
});
}
return true;
}

View File

@ -4,12 +4,12 @@ namespace App\Models;
/**
* Class FileUser
* App\Models\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,6 +18,7 @@ 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

View File

@ -5,6 +5,7 @@
:transfer="transfer"
:remote-method="searchUser"
:placeholder="placeholder"
:size="size"
:loading="loading"
:loading-text="$L('加载中...')"
:default-label="value"
@ -17,6 +18,7 @@
@on-open-change="openChange"
@on-set-default-options="setDefaultOptions">
<div v-if="multipleMax" slot="drop-prepend" class="user-drop-prepend">{{$L('最多只能选择' + multipleMax + '')}}</div>
<slot name="option-prepend"></slot>
<Option
v-for="(item, key) in list"
:value="item.userid"
@ -60,6 +62,9 @@
placeholder: {
default: ''
},
size: {
default: 'default'
},
transfer: {
type: Boolean,
default: true

View File

@ -198,21 +198,46 @@
<Modal
v-model="shareShow"
:title="$L('共享设置')"
:mask-closable="false">
<Form ref="addProject" :model="shareInfo" label-width="auto" @submit.native.prevent>
<FormItem prop="type" :label="$L('共享对象')">
<RadioGroup v-model="shareInfo.share">
<Radio v-if="userIsAdmin" :label="1">{{$L('所有人')}}</Radio>
<Radio :label="2">{{$L('指定成员')}}</Radio>
</RadioGroup>
:mask-closable="false"
footer-hide>
<Form class="page-file-share-form" :model="shareInfo" @submit.native.prevent inline>
<FormItem prop="userids" class="share-userid">
<UserInput
v-model="shareInfo.userids"
:disabledChoice="shareAlready"
:multiple-max="100"
:placeholder="$L('选择共享成员')">
<Option slot="option-prepend" :value="0" :label="$L('所有人')">
<div class="user-input-option">
<div class="user-input-avatar"><EAvatar class="avatar" style="line-height:26px" icon="el-icon-s-custom"/></div>
<div class="user-input-nickname">{{ $L('所有人') }}</div>
<div class="user-input-userid">All</div>
</div>
</Option>
</UserInput>
</FormItem>
<FormItem v-if="shareInfo.share === 2" prop="userids" :label="$L('共享成员')">
<UserInput v-if="!shareInfo.userTmpHide" v-model="shareInfo.userids" :disabledChoice="[shareInfo.userid]" :multiple-max="100" :placeholder="$L('选择共享成员')"/>
<FormItem>
<Select v-model="shareInfo.permission" :placeholder="$L('权限')">
<Option :value="1">{{$L('读/写')}}</Option>
<Option :value="0">{{$L('只读')}}</Option>
</Select>
</FormItem>
<FormItem>
<Button type="primary" :loading="shareLoad > 0" @click="onShare">{{$L('共享')}}</Button>
</FormItem>
</Form>
<div slot="footer" class="adaption">
<Button type="default" :loading="shareLoad > 0" @click="onShare(false)">{{$L('取消共享')}}</Button>
<Button type="primary" :loading="shareLoad > 0" @click="onShare(true)">{{$L('设置共享')}}</Button>
<div v-if="shareList.length > 0">
<div class="page-file-share-title">{{ $L('已共享成员') }}:</div>
<ul class="page-file-share-list">
<li v-for="item in shareList">
<UserAvatar :size="32" :userid="item.userid" show-name tooltip-disabled/>
<Select v-model="item.permission" :placeholder="$L('权限')" @on-change="upShare(item)">
<Option :value="1">{{ $L('读/写') }}</Option>
<Option :value="0">{{ $L('只读') }}</Option>
<Option :value="-1" class="delete">{{ $L('删除') }}</Option>
</Select>
</li>
</ul>
</div>
</Modal>
@ -308,7 +333,8 @@ export default {
columns: [],
shareShow: false,
shareInfo: {},
shareInfo: {id: 0, userid: 0, permission: 1},
shareList: [],
shareLoad: 0,
editShow: false,
@ -381,6 +407,14 @@ export default {
return null;
},
shareAlready() {
let data = this.shareList ? this.shareList.map(({userid}) => userid) : [];
if (this.shareInfo.userid) {
data.push(this.shareInfo.userid);
}
return data
},
fileList() {
const {files, searchKey, pid} = this;
return sortBy(files.filter((file) => {
@ -747,15 +781,10 @@ export default {
case 'share':
this.shareInfo = {
id: item.id,
name: item.name,
userid: item.userid,
share: item.share,
_share: item.share,
permission: 1,
};
if (!this.userIsAdmin) {
//
this.shareInfo.share = 2;
}
this.shareList = [];
this.shareShow = true;
this.getShare();
break;
@ -899,10 +928,10 @@ export default {
}).then(({data}) => {
this.shareLoad--;
if (data.id == this.shareInfo.id) {
this.shareInfo = Object.assign({userTmpHide: true}, this.shareInfo, data);
this.$nextTick(() => {
this.$set(this.shareInfo, 'userTmpHide', false);
})
this.shareList = data.list.map(item => {
item._permission = item.permission;
return item;
});
}
}).catch(({msg}) => {
this.shareLoad--;
@ -911,32 +940,58 @@ export default {
})
},
onShare(share) {
if (!share && !this.shareInfo._share) {
this.shareShow = false;
return;
}
if (![1, 2].includes(this.shareInfo.share)) {
$A.messageWarning("请选择共享对象")
onShare() {
if (this.shareInfo.userids.length == 0) {
$A.messageWarning("请选择共享成员")
return;
}
this.shareLoad++;
this.$store.dispatch("call", {
url: 'file/share/update',
data: Object.assign(this.shareInfo, {
action: share ? 'share' : 'unshare'
}),
data: this.shareInfo,
}).then(({data, msg}) => {
this.shareLoad--;
this.shareShow = false;
$A.messageSuccess(msg)
this.$store.dispatch("saveFile", data);
this.$set(this.shareInfo, 'userids', []);
this.getShare();
}).catch(({msg}) => {
this.shareLoad--;
$A.modalError(msg)
})
},
upShare(item) {
if (item.loading === true) {
return;
}
item.loading = true;
//
this.$store.dispatch("call", {
url: 'file/share/update',
data: {
id: this.shareInfo.id,
userids: [item.userid],
permission: item.permission,
},
}).then(({data, msg}) => {
item.loading = false;
item._permission = item.permission;
$A.messageSuccess(msg);
this.$store.dispatch("saveFile", data);
if (item.permission === -1) {
let index = this.shareList.findIndex(({userid}) => userid == item.userid);
if (index > -1) {
this.shareList.splice(index, 1)
}
}
}).catch(({msg}) => {
item.loading = false;
item.permission = item._permission;
$A.modalError(msg)
})
},
/********************文件上传部分************************/
uploadUpdate(fileList) {

View File

@ -703,6 +703,44 @@
}
}
.page-file-share-form {
display: flex;
margin-bottom: 12px;
.share-userid {
flex: 1;
}
> div {
flex-shrink: 0;
&:last-child {
margin-right: 0;
}
}
}
.page-file-share-title {
margin-top: -8px;
margin-bottom: 14px;
padding: 0 2px;
}
.page-file-share-list {
max-height: 500px;
margin-bottom: 24px;
> li {
display: flex;
align-items: center;
margin-bottom: 12px;
.common-avatar {
flex: 1;
}
.ivu-select {
width: auto;
flex-shrink: 0;
}
.delete {
color: #ff0000;
}
}
}
.page-file-drawer {
.overlay-content {
border-radius: 20px 20px 0 0 !important;