mirror of https://github.com/halo-dev/halo-admin
feat: links and link groups support drag and drop sorting (#574)
refactor LinkList.vue, use Vue.Draggable to sort links and teams via dragging <!-- Thanks for sending a pull request! Here are some tips for you: 1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>。 1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>. 2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。 2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. 3. 请确保你已经添加并运行了适当的测试。 3. Ensure you have added or ran the appropriate tests for your PR. --> #### What type of PR is this? /kind feature <!-- 添加其中一个类别: Add one of the following kinds: /kind bug /kind cleanup /kind documentation /kind feature /kind optimization 适当添加其中一个或多个类别(可选): Optionally add one or more of the following kinds if applicable: /kind api-change /kind deprecation /kind failing-test /kind flake /kind regression --> #### What this PR does / why we need it: 使用Vue.Draggable重构了友链功能。现在可以通过可视化拖拽对友链或整个分组进行排序。支持友链移入/移出分组。 #### Which issue(s) this PR fixes: <!-- PR 合并时自动关闭 issue。 Automatically closes linked issue when PR is merged. 用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)` Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`. --> Fixes # 1905 #### Screenshots: <!-- 如果此 PR 有 UI 的改动,最好截图说明这个 PR 的改动。 If there are UI changes to this PR, it is best to take a screenshot to illustrate the changes to this PR. eg. Before:  After:  --> 演示视频: <video src="https://user-images.githubusercontent.com/65994555/169685416-e4b86306-bd96-4e5a-bbde-d40f6383d9ca.mp4"></video> #### Special notes for your reviewer: #### Does this PR introduce a user-facing change? <!-- 如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。 否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change), Release Note 需要以 `action required` 开头。 If no, just write "NONE" in the release-note block below. If yes, a release note is required: Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required". --> ```release-note 重构了管理友链的界面,现在可以通过拖拽的形式可视化的管理友链及友链分组的排序 ```pull/597/head
parent
ca8f1f138b
commit
6f9fe25a3e
|
@ -23,7 +23,7 @@
|
|||
"@codemirror/basic-setup": "^0.19.3",
|
||||
"@codemirror/lang-html": "^0.19.4",
|
||||
"@codemirror/lang-java": "^0.19.1",
|
||||
"@halo-dev/admin-api": "^1.0.0",
|
||||
"@halo-dev/admin-api": "^1.1.0",
|
||||
"@halo-dev/editor": "^3.0.5",
|
||||
"ant-design-vue": "^1.7.8",
|
||||
"dayjs": "^1.11.0",
|
||||
|
|
|
@ -7,7 +7,7 @@ specifiers:
|
|||
'@codemirror/basic-setup': ^0.19.3
|
||||
'@codemirror/lang-html': ^0.19.4
|
||||
'@codemirror/lang-java': ^0.19.1
|
||||
'@halo-dev/admin-api': ^1.0.0
|
||||
'@halo-dev/admin-api': ^1.1.0
|
||||
'@halo-dev/editor': ^3.0.5
|
||||
'@tailwindcss/aspect-ratio': ^0.4.0
|
||||
'@vue/cli-plugin-babel': ~5.0.4
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
<template>
|
||||
<a-modal :visible="form.visible" :title="title" :closable="false" :maskClosable="false">
|
||||
<a-form-model ref="linkForm" :model="form.model" :rules="rules" layout="horizontal">
|
||||
<a-form-model-item label="网站名称:" prop="name">
|
||||
<a-input v-model="form.model.name" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item help="* 需要加上 http://" label="网站地址:" prop="url">
|
||||
<a-input v-model="form.model.url" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="Logo:" prop="logo">
|
||||
<a-input v-model="form.model.logo" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="分组:" prop="team">
|
||||
<a-auto-complete v-model="form.model.team" :dataSource="teams" allowClear />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="描述:" prop="description">
|
||||
<a-input v-model="form.model.description" :autoSize="{ minRows: 5 }" type="textarea" />
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
<template #footer>
|
||||
<ReactiveButton
|
||||
:errored="form.errored"
|
||||
:loading="form.saving"
|
||||
erroredText="保存失败"
|
||||
loadedText="保存成功"
|
||||
text="保存"
|
||||
type="primary"
|
||||
@callback="$emit('saved')"
|
||||
@click="handleCreateOrUpdateLink"
|
||||
></ReactiveButton>
|
||||
<a-button @click="$emit('close')">取消</a-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'LinkCreateModal',
|
||||
props: {
|
||||
form_: Object,
|
||||
teams: Array
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '* 友情链接名称不能为空', trigger: ['change'] },
|
||||
{ max: 255, message: '* 友情链接名称的字符长度不能超过 255', trigger: ['change'] }
|
||||
],
|
||||
url: [
|
||||
{ required: true, message: '* 友情链接地址不能为空', trigger: ['change'] },
|
||||
{ max: 1023, message: '* 友情链接地址的字符长度不能超过 1023', trigger: ['change'] },
|
||||
{ type: 'url', message: '* 友情链接地址格式有误', trigger: ['change'] }
|
||||
],
|
||||
logo: [{ max: 1023, message: '* 友情链接 Logo 的字符长度不能超过 1023', trigger: ['change'] }],
|
||||
description: [{ max: 255, message: '* 友情链接描述的字符长度不能超过 255', trigger: ['change'] }],
|
||||
team: [{ max: 255, message: '* 友情链接分组的字符长度 255', trigger: ['change'] }]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
form: {
|
||||
get() {
|
||||
return this.form_
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('update:form', value)
|
||||
}
|
||||
},
|
||||
title() {
|
||||
if (this.isUpdateMode) {
|
||||
return '修改友情链接'
|
||||
}
|
||||
return '添加友情链接'
|
||||
},
|
||||
isUpdateMode() {
|
||||
return !!this.form.model.id
|
||||
},
|
||||
dragOptions() {
|
||||
return {
|
||||
animation: 200,
|
||||
disabled: false,
|
||||
ghostClass: 'ghost'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleCreateOrUpdateLink() {
|
||||
const _this = this
|
||||
_this.$refs.linkForm.validate(valid => {
|
||||
if (valid) {
|
||||
_this.$emit('createOrUpdateLink')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -1,139 +1,88 @@
|
|||
<template>
|
||||
<page-view>
|
||||
<template #extra>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="form.visible = true">添加</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<LinkCreateModal
|
||||
:form_.sync="form"
|
||||
:teams="computedTeams"
|
||||
@close="
|
||||
form.visible = false
|
||||
form.model = {}
|
||||
"
|
||||
@createOrUpdateLink="handleCreateOrUpdateLink"
|
||||
@saved="handleSavedCallback"
|
||||
/>
|
||||
<a-row :gutter="12">
|
||||
<a-col :lg="10" :md="10" :sm="24" :xl="10" :xs="24" class="pb-3">
|
||||
<a-card :bodyStyle="{ padding: '16px' }" :title="title">
|
||||
<a-form-model ref="linkForm" :model="form.model" :rules="form.rules" layout="horizontal">
|
||||
<a-form-model-item label="网站名称:" prop="name">
|
||||
<a-input v-model="form.model.name" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item help="* 需要加上 http://" label="网站地址:" prop="url">
|
||||
<a-input v-model="form.model.url" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="Logo:" prop="logo">
|
||||
<a-input v-model="form.model.logo" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="分组:" prop="team">
|
||||
<a-auto-complete v-model="form.model.team" :dataSource="computedTeams" allowClear />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="排序编号:" prop="priority">
|
||||
<a-input-number v-model="form.model.priority" :min="0" style="width: 100%" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item label="描述:" prop="description">
|
||||
<a-input v-model="form.model.description" :autoSize="{ minRows: 5 }" type="textarea" />
|
||||
</a-form-model-item>
|
||||
<a-form-model-item>
|
||||
<ReactiveButton
|
||||
v-if="!isUpdateMode"
|
||||
:errored="form.errored"
|
||||
:loading="form.saving"
|
||||
erroredText="保存失败"
|
||||
loadedText="保存成功"
|
||||
text="保存"
|
||||
type="primary"
|
||||
@callback="handleSavedCallback"
|
||||
@click="handleCreateOrUpdateLink"
|
||||
></ReactiveButton>
|
||||
<a-button-group v-else>
|
||||
<ReactiveButton
|
||||
:errored="form.errored"
|
||||
:loading="form.saving"
|
||||
erroredText="更新失败"
|
||||
loadedText="更新成功"
|
||||
text="更新"
|
||||
type="primary"
|
||||
@callback="handleSavedCallback"
|
||||
@click="handleCreateOrUpdateLink"
|
||||
></ReactiveButton>
|
||||
<a-button v-if="isUpdateMode" type="dashed" @click="form.model = {}">返回添加</a-button>
|
||||
</a-button-group>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :lg="14" :md="14" :sm="24" :xl="14" :xs="24" class="pb-3">
|
||||
<a-card :bodyStyle="{ padding: '16px' }" title="所有友情链接">
|
||||
<!-- Mobile -->
|
||||
<a-list
|
||||
v-if="isMobile()"
|
||||
:dataSource="table.data"
|
||||
:loading="table.loading"
|
||||
itemLayout="vertical"
|
||||
size="large"
|
||||
>
|
||||
<a-list-item :key="index" slot="renderItem" slot-scope="item, index">
|
||||
<template slot="actions">
|
||||
<a-dropdown :trigger="['click']" placement="topLeft">
|
||||
<span>
|
||||
<a-icon type="bars" />
|
||||
</span>
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item @click="form.model = item">编辑</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-popconfirm
|
||||
:title="'你确定要删除【' + item.name + '】链接?'"
|
||||
cancelText="取消"
|
||||
okText="确定"
|
||||
@confirm="handleDeleteLink(item.id)"
|
||||
>
|
||||
删除
|
||||
</a-popconfirm>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
<a-col :span="24" class="pb-3">
|
||||
<a-empty v-if="linkTeam.length === 0" />
|
||||
<draggable
|
||||
v-else
|
||||
:list="linkTeam"
|
||||
class="list-group"
|
||||
group="pull: 'false', put: false"
|
||||
handle=".mover"
|
||||
v-bind="dragOptions"
|
||||
@update="handleUpdateInBatch"
|
||||
>
|
||||
<transition-group type="transition">
|
||||
<a-card
|
||||
v-for="team in linkTeam"
|
||||
:key="team.team"
|
||||
:bodyStyle="{ padding: '16px' }"
|
||||
style="margin-bottom: 10px"
|
||||
>
|
||||
<template #title>
|
||||
{{ team.team ? team.team : '默认分组' }}
|
||||
<a-icon class="cursor-move mover ml-1 list-group-item" type="bars" />
|
||||
</template>
|
||||
<template slot="extra">
|
||||
<span>
|
||||
{{ item.team }}
|
||||
</span>
|
||||
</template>
|
||||
<a-list-item-meta>
|
||||
<template slot="description">
|
||||
{{ item.description }}
|
||||
</template>
|
||||
<span
|
||||
slot="title"
|
||||
style="
|
||||
max-width: 300px;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
"
|
||||
>
|
||||
{{ item.name }}
|
||||
</span>
|
||||
</a-list-item-meta>
|
||||
<a :href="item.url" target="_blank">{{ item.url }}</a>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
<!-- Desktop -->
|
||||
<a-table
|
||||
v-else
|
||||
:columns="table.columns"
|
||||
:dataSource="table.data"
|
||||
:loading="table.loading"
|
||||
:rowKey="link => link.id"
|
||||
:scrollToFirstRowOnChange="true"
|
||||
>
|
||||
<template slot="url" slot-scope="text">
|
||||
<a :href="text" target="_blank">{{ text }}</a>
|
||||
</template>
|
||||
<ellipsis slot="name" slot-scope="text" :length="15" tooltip>{{ text }}</ellipsis>
|
||||
<span slot="action" slot-scope="text, record">
|
||||
<a-button class="!p-0" type="link" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-divider type="vertical" />
|
||||
<a-popconfirm
|
||||
:title="'你确定要删除【' + record.name + '】链接?'"
|
||||
cancelText="取消"
|
||||
okText="确定"
|
||||
@confirm="handleDeleteLink(record.id)"
|
||||
<draggable
|
||||
:list="team.links"
|
||||
group="link"
|
||||
v-bind="dragOptions"
|
||||
@add="modal.lastAdd = team"
|
||||
@remove="handleRemove($event, team)"
|
||||
@update="handleUpdateInBatch"
|
||||
>
|
||||
<a-button class="!p-0" type="link">删除</a-button>
|
||||
</a-popconfirm>
|
||||
</span>
|
||||
</a-table>
|
||||
</a-card>
|
||||
<transition-group
|
||||
class="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
|
||||
type="transition"
|
||||
>
|
||||
<div
|
||||
v-for="link in team.links"
|
||||
:key="link.name"
|
||||
class="cursor-move relative flex items-center space-x-3 rounded border border-solid border-gray-300 bg-white px-2 py-2 shadow-sm hover:border-gray-400 hover:shadow"
|
||||
>
|
||||
<div v-if="link.logo" class="flex-shrink-0">
|
||||
<a-avatar :src="link.logo" class="h-12 w-12 rounded-full" size="large" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-y-1.5 overflow-hidden">
|
||||
<p class="mb-0 truncate text-sm font-medium text-gray-900 truncate">
|
||||
{{ link.name }}
|
||||
</p>
|
||||
<p class="mb-0 truncate text-sm text-gray-500">{{ link.description }}</p>
|
||||
</div>
|
||||
<div class="absolute top-2 right-2 cursor-pointer hover:text-blue-600">
|
||||
<a-dropdown>
|
||||
<div style="width: 30px; display: flex; justify-content: flex-end">
|
||||
<a-icon type="more" />
|
||||
</div>
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item @click="handleEdit(link)"> 编辑</a-menu-item>
|
||||
<a-menu-item @click="handleDeleteLink(link.id)"> 删除</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</draggable>
|
||||
</a-card>
|
||||
</transition-group>
|
||||
</draggable>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<div style="position: fixed; bottom: 30px; right: 30px">
|
||||
|
@ -161,82 +110,46 @@
|
|||
<script>
|
||||
import { PageView } from '@/layouts'
|
||||
import { mapActions } from 'vuex'
|
||||
import draggable from 'vuedraggable'
|
||||
import { mixin, mixinDevice } from '@/mixins/mixin.js'
|
||||
import apiClient from '@/utils/api-client'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
ellipsis: true,
|
||||
scopedSlots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: '网址',
|
||||
dataIndex: 'url',
|
||||
ellipsis: true,
|
||||
scopedSlots: { customRender: 'url' }
|
||||
},
|
||||
{
|
||||
title: '分组',
|
||||
ellipsis: true,
|
||||
dataIndex: 'team'
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
dataIndex: 'priority'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
scopedSlots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
import LinkCreateModal from '@/views/sheet/components/LinkCreateModal'
|
||||
import { Modal } from 'ant-design-vue'
|
||||
export default {
|
||||
mixins: [mixin, mixinDevice],
|
||||
components: {
|
||||
PageView
|
||||
LinkCreateModal,
|
||||
PageView,
|
||||
draggable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
modal: {
|
||||
toDelete: [],
|
||||
visible: false,
|
||||
newIndex: null,
|
||||
lastAdd: null,
|
||||
lastRemove: null
|
||||
},
|
||||
table: {
|
||||
columns,
|
||||
data: [],
|
||||
loading: false
|
||||
},
|
||||
form: {
|
||||
visible: false,
|
||||
model: {},
|
||||
saving: false,
|
||||
errored: false,
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '* 友情链接名称不能为空', trigger: ['change'] },
|
||||
{ max: 255, message: '* 友情链接名称的字符长度不能超过 255', trigger: ['change'] }
|
||||
],
|
||||
url: [
|
||||
{ required: true, message: '* 友情链接地址不能为空', trigger: ['change'] },
|
||||
{ max: 1023, message: '* 友情链接地址的字符长度不能超过 1023', trigger: ['change'] },
|
||||
{ type: 'url', message: '* 友情链接地址格式有误', trigger: ['change'] }
|
||||
],
|
||||
logo: [{ max: 1023, message: '* 友情链接 Logo 的字符长度不能超过 1023', trigger: ['change'] }],
|
||||
description: [{ max: 255, message: '* 友情链接描述的字符长度不能超过 255', trigger: ['change'] }],
|
||||
team: [{ max: 255, message: '* 友情链接分组的字符长度 255', trigger: ['change'] }]
|
||||
}
|
||||
errored: false
|
||||
},
|
||||
optionsModal: {
|
||||
visible: false,
|
||||
data: []
|
||||
},
|
||||
teams: []
|
||||
teams: [],
|
||||
linkTeam: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
if (this.isUpdateMode) {
|
||||
return '修改友情链接'
|
||||
}
|
||||
return '添加友情链接'
|
||||
},
|
||||
isUpdateMode() {
|
||||
return !!this.form.model.id
|
||||
},
|
||||
|
@ -244,6 +157,13 @@ export default {
|
|||
return this.teams.filter(item => {
|
||||
return item !== ''
|
||||
})
|
||||
},
|
||||
dragOptions() {
|
||||
return {
|
||||
animation: 200,
|
||||
disabled: false,
|
||||
ghostClass: 'ghost'
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -253,12 +173,87 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
...mapActions(['refreshOptionsCache']),
|
||||
getPriority() {
|
||||
const params = []
|
||||
for (const team of this.linkTeam) {
|
||||
for (const link of team.links) {
|
||||
link.team = team.team
|
||||
params.push(link)
|
||||
}
|
||||
}
|
||||
let priority = params.length
|
||||
for (const link of params) {
|
||||
link.priority = priority--
|
||||
}
|
||||
return params
|
||||
},
|
||||
handleUpdateInBatch() {
|
||||
const params = this.getPriority()
|
||||
apiClient.link.updateInBatch(params).finally(() => {
|
||||
this.table.loading = false
|
||||
})
|
||||
},
|
||||
removeConfirm() {
|
||||
Modal.confirm({
|
||||
title: '确定移出分组吗',
|
||||
content: '移出最后一个链接后,该分组将消失。确定要移出分组吗?',
|
||||
onCancel: () => {
|
||||
this.recoverTeam()
|
||||
},
|
||||
onOk: () => {
|
||||
this.removeTeam()
|
||||
}
|
||||
})
|
||||
},
|
||||
removeTeam() {
|
||||
this.linkTeam.splice(this.linkTeam.indexOf(this.modal.lastRemove), 1)
|
||||
this.modal.newIndex = null
|
||||
},
|
||||
recoverTeam() {
|
||||
const recover = this.modal.lastAdd.links.splice(this.modal.newIndex, 1)
|
||||
this.modal.lastRemove.links.push(recover[0])
|
||||
this.modal.newIndex = null
|
||||
},
|
||||
handleRemove(evt, team) {
|
||||
this.modal.lastRemove = team
|
||||
if (team.links.length === 0) {
|
||||
this.modal.newIndex = evt.newIndex
|
||||
this.removeConfirm()
|
||||
}
|
||||
this.handleUpdateInBatch()
|
||||
},
|
||||
splitIntoTeam(data) {
|
||||
const teamMap = new Map()
|
||||
for (const link of data) {
|
||||
if (teamMap.has(link.team)) {
|
||||
const team = teamMap.get(link.team)
|
||||
team.links.push(link)
|
||||
if (team.priority < link.priority) {
|
||||
team.priority = link.priority
|
||||
}
|
||||
} else {
|
||||
const team = {
|
||||
team: link.team,
|
||||
priority: link.priority,
|
||||
links: [link]
|
||||
}
|
||||
teamMap.set(link.team, team)
|
||||
}
|
||||
}
|
||||
this.linkTeam = Array.from(teamMap.values()).sort((a, b) => {
|
||||
return b.priority - a.priority
|
||||
})
|
||||
},
|
||||
handleListLinks() {
|
||||
this.table.loading = true
|
||||
apiClient.link
|
||||
.list()
|
||||
.then(response => {
|
||||
this.table.data = response.data
|
||||
this.table.data.sort((a, b) => {
|
||||
return b.priority - a.priority
|
||||
})
|
||||
this.splitIntoTeam(this.table.data)
|
||||
})
|
||||
.finally(() => {
|
||||
this.table.loading = false
|
||||
|
@ -275,8 +270,8 @@ export default {
|
|||
})
|
||||
},
|
||||
handleEdit(record) {
|
||||
this.form.model = record
|
||||
this.$refs.linkForm.clearValidate()
|
||||
this.form.visible = true
|
||||
this.form.model = Object.assign({}, record)
|
||||
},
|
||||
handleDeleteLink(id) {
|
||||
apiClient.link
|
||||
|
@ -290,35 +285,75 @@ export default {
|
|||
})
|
||||
},
|
||||
handleCreateOrUpdateLink() {
|
||||
const _this = this
|
||||
_this.$refs.linkForm.validate(valid => {
|
||||
if (valid) {
|
||||
_this.form.saving = true
|
||||
if (_this.isUpdateMode) {
|
||||
apiClient.link
|
||||
.update(_this.form.model.id, _this.form.model)
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
})
|
||||
this.form.saving = true
|
||||
if (this.isUpdateMode) {
|
||||
let toTeam, fromTeam, removeId
|
||||
for (const team of this.linkTeam) {
|
||||
if (toTeam && fromTeam) {
|
||||
break
|
||||
}
|
||||
if (team.team === this.form.model.team) {
|
||||
for (let link of team.links) {
|
||||
if (link.id === this.form.model.id) {
|
||||
// 分组没有改变, 直接update即可
|
||||
apiClient.link
|
||||
.update(this.form.model.id, this.form.model)
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.form.saving = false
|
||||
}, 400)
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
toTeam = team
|
||||
} else {
|
||||
apiClient.link
|
||||
.create(_this.form.model)
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
_this.form.saving = false
|
||||
}, 400)
|
||||
})
|
||||
for (let i = 0; i < team.links.length; i++) {
|
||||
if (team.links[i].id === this.form.model.id) {
|
||||
fromTeam = team
|
||||
removeId = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
if (!toTeam) {
|
||||
toTeam = {
|
||||
links: [],
|
||||
priority: -1,
|
||||
team: this.form.model.team
|
||||
}
|
||||
this.linkTeam.push(toTeam)
|
||||
}
|
||||
|
||||
toTeam.links.push(this.form.model)
|
||||
fromTeam.links.splice(removeId, 1)
|
||||
const params = this.getPriority()
|
||||
apiClient.link
|
||||
.updateInBatch(params)
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.form.saving = false
|
||||
}, 400)
|
||||
})
|
||||
} else {
|
||||
apiClient.link
|
||||
.create(this.form.model)
|
||||
.catch(() => {
|
||||
this.form.errored = true
|
||||
})
|
||||
.finally(() => {
|
||||
setTimeout(() => {
|
||||
this.form.saving = false
|
||||
}, 400)
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSavedCallback() {
|
||||
if (this.form.errored) {
|
||||
|
@ -327,6 +362,7 @@ export default {
|
|||
this.form.model = {}
|
||||
this.handleListLinks()
|
||||
this.handleListLinkTeams()
|
||||
this.form.visible = false
|
||||
}
|
||||
},
|
||||
handleSaveOptions() {
|
||||
|
@ -344,3 +380,11 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.list-group {
|
||||
min-height: 20px;
|
||||
}
|
||||
.list-group-item {
|
||||
cursor: move;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in New Issue