147 lines
4.7 KiB
Vue
147 lines
4.7 KiB
Vue
<!-- eslint-disable vue/no-v-model-argument -->
|
||
<template>
|
||
<el-dialog
|
||
v-model="visible"
|
||
title="设置分享人员"
|
||
width="620px"
|
||
class="doclib-dialog dialog-form-layout"
|
||
align-center
|
||
destroy-on-close
|
||
:close-on-click-modal="!saving"
|
||
:close-on-press-escape="!saving"
|
||
:show-close="!saving"
|
||
>
|
||
<p class="doclib-summary">{{ summaryText }}</p>
|
||
<el-form label-position="top">
|
||
<el-form-item>
|
||
<template #label
|
||
>分享给<span class="form-label-tip"
|
||
>可多选,取消选择即收回访问权限;保存后对所选文档整份覆盖</span
|
||
></template
|
||
>
|
||
<el-select
|
||
v-model="userIds"
|
||
multiple
|
||
filterable
|
||
remote
|
||
reserve-keyword
|
||
:remote-method="searchUsers"
|
||
:loading="loading"
|
||
:disabled="saving"
|
||
placeholder="搜索同租户人员姓名或账号"
|
||
class="doclib-full-width"
|
||
>
|
||
<el-option
|
||
v-for="person in options"
|
||
:key="person.id"
|
||
:value="person.id"
|
||
:label="person.name"
|
||
>
|
||
<span>{{ person.name }}</span
|
||
><span class="doclib-person-dept">{{ person.deptName || '未分配部门' }}</span>
|
||
</el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-form>
|
||
<p class="doclib-muted">分享人员可以查看和下载文档,不能删除或修改分享设置。</p>
|
||
<template #footer>
|
||
<el-button :disabled="saving" @click="visible = false"
|
||
><el-icon><Close /></el-icon>取消</el-button
|
||
>
|
||
<el-button type="primary" :loading="saving" @click="save"
|
||
><el-icon><Check /></el-icon>保存分享</el-button
|
||
>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|
||
<script setup lang="ts">
|
||
import { Close, Check } from '@element-plus/icons-vue'
|
||
import {
|
||
fetchDoclibUsers,
|
||
saveDoclibBatchShares,
|
||
type DoclibDocument,
|
||
type DoclibPerson
|
||
} from '@/api/doclib'
|
||
import { createLatestRequest, shareUserIntersection } from './model'
|
||
const props = defineProps<{ modelValue: boolean; documents: DoclibDocument[] }>()
|
||
const emit = defineEmits<{
|
||
'update:modelValue': [value: boolean]
|
||
saved: [documents: DoclibDocument[]]
|
||
}>()
|
||
const visible = computed({
|
||
get: () => props.modelValue,
|
||
set: (value) => {
|
||
if (!saving.value) emit('update:modelValue', value)
|
||
}
|
||
})
|
||
const saving = ref(false)
|
||
const loading = ref(false)
|
||
const userIds = ref<string[]>([])
|
||
const people = ref<DoclibPerson[]>([])
|
||
const requests = createLatestRequest()
|
||
const ownerIds = computed(
|
||
() => new Set(props.documents.map((doc) => doc.ownerId).filter(Boolean))
|
||
)
|
||
const summaryText = computed(() => {
|
||
const names = props.documents.map((doc) => doc.name).filter(Boolean)
|
||
if (!names.length) return '未选择文档'
|
||
if (names.length === 1) return names[0]
|
||
const shown = names.slice(0, 5)
|
||
const more = names.length > 5 ? `等 ${names.length} 个` : ''
|
||
return `已选 ${names.length} 个文档:${shown.join('、')}${more ? ` ${more}` : ''}`
|
||
})
|
||
const options = computed(() => {
|
||
const candidates = new Map<string, DoclibPerson>()
|
||
for (const doc of props.documents) {
|
||
for (const person of doc.shares || []) candidates.set(person.id, person)
|
||
}
|
||
people.value.forEach((person) => candidates.set(person.id, person))
|
||
return [...candidates.values()].filter((person) => !ownerIds.value.has(person.id))
|
||
})
|
||
watch(
|
||
() => props.modelValue,
|
||
(value) => {
|
||
requests.invalidate()
|
||
if (!value) return
|
||
userIds.value = shareUserIntersection(props.documents)
|
||
people.value = []
|
||
void searchUsers('')
|
||
}
|
||
)
|
||
onBeforeUnmount(() => requests.invalidate())
|
||
async function searchUsers(keyword: string) {
|
||
const token = requests.start()
|
||
loading.value = true
|
||
try {
|
||
const result = await fetchDoclibUsers(keyword.trim())
|
||
if (requests.isCurrent(token)) {
|
||
const retained = people.value.filter((person) => userIds.value.includes(person.id))
|
||
people.value = [...retained, ...result]
|
||
}
|
||
} catch {
|
||
/* 请求层统一展示错误 */
|
||
} finally {
|
||
if (requests.isCurrent(token)) loading.value = false
|
||
}
|
||
}
|
||
async function save() {
|
||
if (!props.documents.length || props.documents.some((doc) => !doc.canManage) || saving.value) {
|
||
return
|
||
}
|
||
saving.value = true
|
||
try {
|
||
const updated = await saveDoclibBatchShares(
|
||
props.documents.map((doc) => doc.id),
|
||
userIds.value
|
||
)
|
||
ElMessage.success('分享设置已保存')
|
||
emit('saved', updated || [])
|
||
emit('update:modelValue', false)
|
||
} catch {
|
||
/* 请求层统一展示错误 */
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
</script>
|