feat:表格拖拽排序api

This commit is contained in:
妙码生花 2022-03-10 22:50:16 +08:00
parent 66f81332b3
commit 6f201d8e43
10 changed files with 147 additions and 35 deletions

View File

@ -1,17 +1,18 @@
<?php
return [
'Username' => 'User Name',
'Password' => 'Password',
'Captcha' => 'Captcha',
'CaptchaId' => 'Captcha Id',
'Please enter the correct verification code' => 'Please enter the correct verification code!',
'Parameter %s can not be empty' => 'Parameter %s can not be empty',
'Record not found' => 'Record not found',
'No rows were added' => 'No rows were added',
'No rows were deleted' => 'No rows were deleted',
'No rows updated' => 'No rows updated',
'Update successful' => 'Update successful!',
'Added successfully' => 'Added successfully!',
'Deleted successfully' => 'Deleted successfully!',
'Parameter error' => 'Parameter error!',
'Username' => 'User Name',
'Password' => 'Password',
'Captcha' => 'Captcha',
'CaptchaId' => 'Captcha Id',
'Please enter the correct verification code' => 'Please enter the correct verification code!',
'Parameter %s can not be empty' => 'Parameter %s can not be empty',
'Record not found' => 'Record not found',
'No rows were added' => 'No rows were added',
'No rows were deleted' => 'No rows were deleted',
'No rows updated' => 'No rows updated',
'Update successful' => 'Update successful!',
'Added successfully' => 'Added successfully!',
'Deleted successfully' => 'Deleted successfully!',
'Parameter error' => 'Parameter error!',
'Invalid collation because the weights of the two targets are equal' => 'Invalid collation because the weights of the two targets are equal',
];

View File

@ -1,17 +1,18 @@
<?php
return [
'Username' => '用户名',
'Password' => '密码',
'Captcha' => '验证码',
'CaptchaId' => '验证码ID',
'Please enter the correct verification code' => '请输入正确的验证码!',
'Parameter %s can not be empty' => '参数%s不能为空',
'Record not found' => '记录未找到',
'No rows were added' => '未添加任何行',
'No rows were deleted' => '未删除任何行',
'No rows updated' => '未更新任何行',
'Update successful' => '更新成功!',
'Added successfully' => '添加成功!',
'Deleted successfully' => '删除成功!',
'Parameter error' => '参数错误!',
'Username' => '用户名',
'Password' => '密码',
'Captcha' => '验证码',
'CaptchaId' => '验证码ID',
'Please enter the correct verification code' => '请输入正确的验证码!',
'Parameter %s can not be empty' => '参数%s不能为空',
'Record not found' => '记录未找到',
'No rows were added' => '未添加任何行',
'No rows were deleted' => '未删除任何行',
'No rows updated' => '未更新任何行',
'Update successful' => '更新成功!',
'Added successfully' => '添加成功!',
'Deleted successfully' => '删除成功!',
'Parameter error' => '参数错误!',
'Invalid collation because the weights of the two targets are equal' => '无效排序整理,因为两个目标权重是相等的',
];

View File

@ -3,6 +3,7 @@
namespace app\admin\library\traits;
use Exception;
use think\facade\Config;
use think\facade\Db;
use think\db\exception\PDOException;
use think\exception\ValidateException;
@ -12,7 +13,7 @@ trait Backend
protected function excludeFields($params)
{
if (!is_array($this->preExcludeFields)) {
$this->preExcludeFields = explode(',', $this->preExcludeFields);
$this->preExcludeFields = explode(',', (string)$this->preExcludeFields);
}
foreach ($this->preExcludeFields as $field) {
@ -132,4 +133,39 @@ trait Backend
$this->error(__('No rows were deleted'));
}
}
public function sortable($id, $targetId)
{
$row = $this->model->find($id);
$target = $this->model->find($targetId);
if (!$row || !$target) {
$this->error(__('Record not found'));
}
if ($row[$this->weighField] == $target[$this->weighField]) {
$autoSortEqWeight = is_null($this->autoSortEqWeight) ? Config::get('buildadmin.auto_sort_eq_weight') : $this->autoSortEqWeight;
if (!$autoSortEqWeight) {
$this->error(__('Invalid collation because the weights of the two targets are equal'));
}
// 自动重新整理排序
$all = $this->model->select();
foreach ($all as $item) {
$item[$this->weighField] = $item[$this->model->getPk()];
$item->save();
}
unset($all);
// 重新获取
$row = $this->model->find($id);
$target = $this->model->find($targetId);
}
$ebak = $target[$this->weighField];
$target[$this->weighField] = $row[$this->weighField];
$row[$this->weighField] = $ebak;
$row->save();
$target->save();
$this->success('');
}
}

View File

@ -19,6 +19,18 @@ class Backend extends Api
protected $model = null;
/**
* 权重(排序)字段
*/
protected $weighField = 'weigh';
/**
* 表格拖拽排序时,两个权重相等则自动重新整理
* config/buildadmin.php文件中的auto_sort_eq_weight为默认值
* null=取默认值,false=,true=
*/
protected $autoSortEqWeight = null;
/**
* 快速搜索字段
*/

View File

@ -9,6 +9,8 @@ return [
'admin_login_captcha' => true,
// 管理员登录失败可重试次数,false则无限
'admin_login_retry' => 10,
// 表格拖拽排序时,两个权重相等则自动重新整理;控制器类中也有此项(作为单控制器自定义配置)
'auto_sort_eq_weight' => false,
// 允许执行的命令
'allowed_commands' => [
'ping-baidu' => 'ping baidu.com',

View File

@ -5,6 +5,7 @@ export const actionUrl = new Map([
['add', controllerUrl + 'add'],
['edit', controllerUrl + 'edit'],
['del', controllerUrl + 'del'],
['sortable', controllerUrl + 'sortable'],
])
export function index(loading: boolean, keyword: string = '') {
@ -58,3 +59,19 @@ export function postData(action: string, data: anyObj) {
}
)
}
export function sortableApi(id: number, targetId: number) {
return createAxios(
{
url: actionUrl.get('sortable'),
method: 'post',
data: {
id: id,
targetId: targetId,
},
},
{
showSuccessMessage: true,
}
)
}

View File

@ -1,7 +1,7 @@
<template>
<div class="table-header">
<el-tooltip v-if="props.buttons.includes('refresh')" content="刷新" placement="top">
<el-button v-blur @click="onAction('refresh')" color="#40485b" class="table-header-operate" type="info">
<el-button v-blur @click="onAction('refresh', { loading: true })" color="#40485b" class="table-header-operate" type="info">
<Icon name="fa fa-refresh" />
</el-button>
</el-tooltip>

View File

@ -100,3 +100,27 @@ const padStart = (str: string, maxLength: number, fillString: string = ' ') => {
}
return fillString.slice(0, fillLength) + str
}
/**
* children的数组降维index所在的行
*/
export const findIndexRow = (data: TableRow[], findIdx: number, keyIndex: number | TableRow = -1): number | TableRow => {
for (const key in data) {
if (typeof keyIndex == 'number') {
keyIndex++
}
if (keyIndex == findIdx) {
return data[key]
}
if (data[key].children) {
keyIndex = findIndexRow(data[key].children!, findIdx, keyIndex)
if (typeof keyIndex != 'number') {
return keyIndex
}
}
}
return keyIndex
}

View File

@ -91,7 +91,7 @@ function createAxios(axiosConfig: AxiosRequestConfig, options: Options = {}, loa
return Promise.reject(response.data)
} else if (options.showSuccessMessage && response.data && response.data.code == 1) {
ElNotification({
title: response.data.msg ? response.data.msg : '操作成功',
message: response.data.msg ? response.data.msg : '操作成功',
type: 'success',
})
}

View File

@ -124,8 +124,8 @@
<script lang="ts" setup>
import { ref, reactive, onUnmounted, onMounted } from 'vue'
import { actionUrl, index, edit, del, postData } from '/@/api/backend/auth/Menu'
import { defaultOptButtons } from '/@/components/table'
import { actionUrl, index, edit, del, postData, sortableApi } from '/@/api/backend/auth/Menu'
import { defaultOptButtons, findIndexRow } from '/@/components/table'
import TableHeader from '/@/components/table/header/index.vue'
import Table from '/@/components/table/index.vue'
import IconSelector from '/@/components/icon/selector.vue'
@ -134,6 +134,7 @@ import useCurrentInstance from '/@/utils/useCurrentInstance'
import Sortable from 'sortablejs'
import { getArrayKey } from '/@/utils/common'
import { useI18n } from 'vue-i18n'
import { ElNotification } from 'element-plus'
const { t } = useI18n()
const { proxy } = useCurrentInstance()
@ -153,6 +154,8 @@ const table: {
dblClickNotEditColumn: (string | undefined)[]
//
column: TableColumn[]
// :pid=1,pid1
dragSortLimitField: string
} = reactive({
pk: 'id',
data: [],
@ -182,6 +185,7 @@ const table: {
buttons: defaultOptButtons(),
},
],
dragSortLimitField: 'pid',
})
/* 表格状态-e */
@ -314,7 +318,8 @@ const onAction = (type: string, data: anyObj) => {
[
'refresh',
() => {
getIndex(true)
table.data = []
getIndex(data.loading ? true : false)
},
],
[
@ -379,7 +384,21 @@ const dragSort = () => {
for (const key in table.column[buttonsKey].buttons) {
table.column[buttonsKey].buttons![key as any].disabledTip = false
}
console.log(evt)
// id
let moveRow = findIndexRow(table.data, evt.oldIndex!) as TableRow
let replaceRow = findIndexRow(table.data, evt.newIndex!) as TableRow
if (moveRow[table.dragSortLimitField] != replaceRow[table.dragSortLimitField]) {
onAction('refresh', {})
ElNotification({
type: 'error',
message: '移动位置超出了可移动范围!',
})
return
}
sortableApi(moveRow.id, replaceRow.id).then((res) => {
onAction('refresh', {})
})
},
})
}