字典完毕

main
expressgy 10 months ago
parent b9b7408f13
commit f952e55e20
  1. 5
      src/common/tools/binarySearch.js
  2. 49
      src/common/tools/binarySearchMore.js
  3. 4
      src/routes/graphResource2/atomModel/index.js
  4. 30
      src/routes/graphResource2/baseDict/index.dto.js
  5. 459
      src/routes/graphResource2/baseDict/index.js
  6. 15
      test/slice.js

@ -31,6 +31,11 @@ export default function binarySearch(arr, id, att) {
}
function getIndexForWhile(list, id, att){
let i = 0
while (i < list.length){

@ -0,0 +1,49 @@
// | ------------------------------------------------------------
// | @版本: version 0.1
// | @创建人: 【Nie-x7129】
// | @E-mail: x71291@outlook.com
// | @所在项目: graphResource2
// | @文件描述: binarySearchMore.js -
// | @创建时间: 2023-12-03 01:54
// | @更新时间: 2023-12-03 01:54
// | @修改记录:
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
// | =
// | ------------------------------------------------------------
function binarySearch2(arr, id, att, bi, ai) {
if(!Object.keys(arr[0]).includes(att)){
throw new Error('不存在属性', att)
}
while (bi <= ai){
const mi = Math.floor((bi + ai)/2);
const miId = arr[mi][att]
if(miId === id){
return mi
}else if(miId < id){
bi = mi + 1
}else{
ai = mi -1
}
}
return -1
}
export default function binarySearchMore(arr, ids, att, bi, ai){
const firstIndex = binarySearch2(arr, ids[0], att, bi, ai);
if(firstIndex != -1){
bi = firstIndex
}
const lastIndex = binarySearch2(arr, ids.slice(-1)[0], att, bi, ai);
if(lastIndex != -1){
ai = lastIndex
}
const indexList = [firstIndex, lastIndex]
if(ids.length -2 == 1){
indexList.push(binarySearch2(arr, ids[1], att, firstIndex, lastIndex))
}else if(ids.length -2 > 1){
indexList.push(...binarySearchMore(arr, ids.slice(1, -1), att, bi, ai))
}
return indexList
}

@ -179,10 +179,12 @@ atomModel.delete('/deleteAtomModelItem', async (ctx, next) => {
RAP.deleteData.push(RAP.objectData[atomModelId])
RAP.length--;
RAP.updatetime = new Date().getTime();
const DeleteTime = new Date().toISOString()
RAP.objectData[atomModelId].isDelete = DeleteTime
ctx.body = { message: '删除元分类/模型成功。' };
await next();
await ctx.sequelize.models.AtomModel.update(
{ isDelete: new Date().toISOString() },
{ isDelete: DeleteTime },
{ where: { atomModelId } },
);
});

@ -121,7 +121,7 @@ export function CreateBaseDictItemDTO(data) {
type: 'object',
properties: {
atomModelId: {
type: ['integer', 'null'],
type: ['integer'],
minimum: 0,
errorMessage: {
type: '元分类/模型ID必须是整数',
@ -139,7 +139,7 @@ export function CreateBaseDictItemDTO(data) {
},
},
baseDictFather:{
type: ['integer', 'null'],
type: ['integer'],
minimum: 0,
default: 0,
errorMessage: {
@ -156,13 +156,20 @@ export function CreateBaseDictItemDTO(data) {
maxLength: '字典项名称长度超出限制2048',
minLength: '字典项名称长度过短',
},
}
},
required: ['baseDictName', 'baseDictDescribe'],
baseDictIdentify:{
type: 'string',
maxLength: 255,
errorMessage: {
type: '字典项标记必须是一个字符串',
maxLength: '字典项名称长度超出限制255',
},
},
},
required: ['baseDictName'],
errorMessage: {
required: {
baseDictName: '字典项名称为必填项',
baseDictDescribe: '字典项描述为必填项'
},
},
};
@ -200,13 +207,20 @@ export function EditBaseDictItemDTO(data) {
maxLength: '字典项名称长度超出限制2048',
minLength: '字典项名称长度过短',
},
}
},
required: ['baseDictName', 'baseDictDescribe', 'baseDictId'],
baseDictIdentify:{
type: 'string',
maxLength: 255,
errorMessage: {
type: '字典项标记必须是一个字符串',
maxLength: '字典项名称长度超出限制255',
},
},
},
required: ['baseDictName', 'baseDictId'],
errorMessage: {
required: {
baseDictName: '字典项名称为必填项',
baseDictDescribe: '字典项描述为必填项',
baseDictId: '字典ID为必填项',
},
},

@ -14,12 +14,15 @@
import Router from 'koa-router';
import {
CreateBaseDictItemDTO,
DeleteBaseDictItemDTO, EditBaseDictItemDTO,
DeleteBaseDictItemDTO,
EditBaseDictItemDTO,
GetBaseDictListDTO,
GetBaseDictStructForBaseDictIdDTO,
GetBaseDictTreeDTO
GetBaseDictTreeDTO,
} from '#routes/graphResource2/baseDict/index.dto.js';
import {makeTreeForList} from "#common/tools/makeTree.js";
import { makeTreeForList } from '#common/tools/makeTree.js';
import binarySearch from '#common/tools/binarySearch.js';
import binarySearchMore from "#common/tools/binarySearchMore.js";
const baseDict = new Router();
@ -30,58 +33,83 @@ baseDict.get('/getBaseDictTree', async (ctx, next) => {
ctx.throw(400, { e: verif.error.map((i) => i.message) });
return;
}
const {atomModelId, reduce} = ctx.query;
const { atomModelId, reduce } = ctx.query;
const RBP = resourceCache.baseDictPool
const isReduce = !(reduce && reduce == 0)
if(atomModelId){
if(Object.keys(RBP.atomModelObject).includes(atomModelId.toString())){
ctx.body = isReduce ? RBP.atomModelObject[atomModelId].reduceBaseDictTree : RBP.atomModelObject[atomModelId].baseDictTree
}else{
ctx.body = isReduce ? RBP.atomModelObject[0].reduceBaseDictTree : RBP.atomModelObject[0].baseDictTree
const RBP = resourceCache.baseDictPool;
// 是否是精简查询
const isReduce = !(reduce && reduce == 0);
if (atomModelId) {
// 按元分类/模型查询
if (Object.keys(RBP.atomModelObject).includes(atomModelId.toString())) {
// 找到了指定的元分类/模型,返回其下的根节点字典树
ctx.body = isReduce
? RBP.atomModelObject[atomModelId].reduceBaseDictTree
: RBP.atomModelObject[atomModelId].baseDictTree;
} else {
// 未找到指定的元分类/模型,返回默认的根节点字典树,基础数据
ctx.body = isReduce
? RBP.atomModelObject[0].reduceBaseDictTree
: RBP.atomModelObject[0].baseDictTree;
}
}else{
ctx.body = isReduce ? RBP.reduceObject[0].children : RBP.atomObject[0].children
} else {
// 没有传递元分类/模型id查所有字典
ctx.body = isReduce
? RBP.reduceObject[0].children
: RBP.atomObject[0].children;
}
});
// @ 获取字典名列表
baseDict.get('/getBaseDictList', async (ctx, next) => {
const verif = GetBaseDictListDTO(ctx.query);
if (!verif.status) return ctx.throw(400, { e: verif.error.map((i) => i.message) });
const {searchData, atomModelId} = ctx.query;
const RBP = resourceCache.baseDictPool
if(atomModelId){
if(Object.keys(RBP.atomModelObject).includes(atomModelId.toString())){
ctx.body = RBP.atomModelObject[atomModelId].reduceBaseDictTree.map(item => ({
if (!verif.status)
return ctx.throw(400, { e: verif.error.map((i) => i.message) });
const { searchData, atomModelId } = ctx.query;
const RBP = resourceCache.baseDictPool;
if (atomModelId) {
// 有元分类/模型id
if (Object.keys(RBP.atomModelObject).includes(atomModelId.toString())) {
// 找到了指定的元分类/模型,返回其下的根节点字典树,不包含子节点
ctx.body = RBP.atomModelObject[atomModelId].reduceBaseDictTree.map(
(item) => ({
atomModel: item.atomModel,
baseDictId: item.baseDictId,
baseDictName: item.baseDictName,
baseDictIdentify: item.baseDictIdentify,
baseDictDescribe: item.baseDictDescribe,
}))
}else{
ctx.body = RBP.atomModelObject[0].reduceBaseDictTree.map(item => ({
}),
);
} else {
// 未找到指定的元分类/模型,返回默认的根节点字典树,基础数据,不包含子节点
ctx.body = RBP.atomModelObject[0].reduceBaseDictTree.map(
(item) => ({
atomModel: item.atomModel,
baseDictId: item.baseDictId,
baseDictName: item.baseDictName,
baseDictIdentify: item.baseDictIdentify,
baseDictDescribe: item.baseDictDescribe,
}))
}),
);
}
}else{
ctx.body = RBP.reduceObject[0].children.map(item => ({
} else {
// 没有传递元分类/模型id查所有根字典,不包含子节点
ctx.body = RBP.reduceObject[0].children.map((item) => ({
atomModel: item.atomModel,
baseDictId: item.baseDictId,
baseDictName: item.baseDictName,
baseDictIdentify: item.baseDictIdentify,
baseDictDescribe: item.baseDictDescribe,
}))
}));
}
if(searchData){
ctx.body = ctx.body.filter(i => {
return (i.baseDictName + i.baseDictIdentify + i.baseDictDescribe).includes(searchData)
})
if (searchData) {
// 如果有模糊查询,对上面返回的数据进行查询过滤
ctx.body = ctx.body.filter((i) => {
return (
i.baseDictName +
i.baseDictIdentify +
i.baseDictDescribe
).includes(searchData);
});
}
});
@ -93,46 +121,373 @@ baseDict.get('/getBaseDictStructForBaseDictId', async (ctx, next) => {
return;
}
const { baseDictId } = ctx.query;
const RBP = resourceCache.baseDictPool
if(Object.keys(RBP.reduceObject).includes(baseDictId.toString())){
ctx.body = RBP.reduceObject[baseDictId]
}else{
ctx.throw(400,{e: '未找到指定字典。'})
const RBP = resourceCache.baseDictPool;
if (Object.keys(RBP.reduceObject).includes(baseDictId.toString())) {
// 找到了目标字典项ID,查其精简树结构
ctx.body = RBP.reduceObject[baseDictId];
} else {
ctx.throw(400, { e: '未找到指定字典。' });
}
});
// @ 删除字典项
baseDict.delete('/deleteBaseDictItem', async (ctx, next) => {
const data = ctx.query;
const verif = DeleteBaseDictItemDTO(data);
const verif = DeleteBaseDictItemDTO(ctx.query);
if (!verif.status) {
ctx.throw(400, { e: verif.error.map((i) => i.message) });
return;
return ctx.throw(400, { e: verif.error.map((i) => i.message) });
}
const baseDictId = ctx.query.baseDictId;
// 查看是否存在该字典项
const RBP = resourceCache.baseDictPool;
if (!(RBP.atomObject[baseDictId] && !RBP.atomObject[baseDictId].isDelete)) {
return ctx.throw(400, { e: '不存在该字典项' });
}
// 获取目标字典项ID及所有子节点id
const baseDictIdList = getAllChildrenBaseDictId(baseDictId);
const deleteTime = new Date().toISOString();
// 修改两个对象中的isDelete
baseDictIdList.push(baseDictId)
for (let i = 0; i < baseDictIdList.length; i++) {
RBP.atomObject[baseDictIdList[i]].isDelete = deleteTime;
RBP.reduceObject[baseDictIdList[i]].isDelete = deleteTime;
}
// 移除normalList的删除项
// 给删除ID排序
baseDictIdList.sort((a, b) => a-b)
// 获取坐标
const indexList = binarySearchMore(RBP.atomNormalList, baseDictIdList, 'baseDictId', 0, RBP.atomNormalList.length)
// 坐标排序
indexList.sort((a, b) => a-b)
// 批量删除
for(let i = indexList.length - 1; i >=0; i--){
// 从后面删除不影响前面的
RBP.atomNormalList.splice(indexList[i], 1)
}
ctx.body = 4
// 增加DeleteList项
RBP.atomDeleteList.push(...baseDictIdList.map(i => RBP.atomObject[i]))
// 将节点从children移出至delChildren
// 移除子元素
moveChildrenToDelChildren(RBP.atomObject[baseDictId]);
moveChildrenToDelChildren(RBP.reduceObject[baseDictId]);
// 移除本身
// 原始值
const fatherBaseDict = RBP.atomObject[RBP.atomObject[baseDictId].baseDictFather];
// 这里使用二分法是因为确定children升序排列,精简和原始位置一样
const index = binarySearch(fatherBaseDict.children, baseDictId, 'baseDictId');
fatherBaseDict.children.splice(index, 1);
fatherBaseDict.delChildren.push(RBP.atomObject[baseDictId])
fatherBaseDict.delChildren.sort((a, b) => a.baseDictId - b.baseDictId)
// 精简值
const fatherBaseDictReduce = RBP.reduceObject[RBP.reduceObject[baseDictId].baseDictFather];
fatherBaseDictReduce.children.splice(index, 1);
fatherBaseDictReduce.delChildren.push(RBP.reduceObject[baseDictId])
fatherBaseDictReduce.delChildren.sort((a, b) => a.baseDictId - b.baseDictId)
ctx.body = {
message: '删除节点成功'
};
await next();
await ctx.sequelize.models.BaseDict.update(
{
isDelete: deleteTime,
},
{ where: { baseDictId: baseDictIdList } },
);
});
// @ 新建字典项
baseDict.post('/createBaseDictItem', async (ctx, next) => {
const data = ctx.request.body;
const verif = CreateBaseDictItemDTO(data);
if (!verif.status) {
ctx.throw(400, { e: verif.error.map((i) => i.message) });
return;
const verif = CreateBaseDictItemDTO(ctx.request.body);
if (!verif.status)
return ctx.throw(400, { e: verif.error.map((i) => i.message) });
const atomModelId = ctx.request.body.atomModelId; // 元分类/模型ID
const baseDictName = ctx.request.body.baseDictName; // 字典项名称
const baseDictFather = ctx.request.body.baseDictFather; // 父节点ID
const baseDictDescribe = ctx.request.body.baseDictDescribe; // 字典项描述
const baseDictIdentify = ctx.request.body.baseDictIdentify; // 字典项标志
const RBP = resourceCache.baseDictPool;
if (baseDictFather == 0) {
// 根节点
if (!atomModelId) {
// 检查是否存在元分类/模型ID
return ctx.throw(400, { e: '根字典需要携带元分类/模型ID' });
}
const hasAtomModel = binarySearch(
resourceCache.atomModelPool.normalData,
atomModelId,
'atomModelId',
);
if (hasAtomModel == -1) {
// 检查是否存在元分类/模型
return ctx.throw(400, { e: '不存在目标元分类/模型' });
}
const check = checkRootDictName(baseDictName, atomModelId);
if (check != -1) {
// 检查是否重名
return ctx.throw(400, { e: '该根字典项在目标元分类/模型下重名' });
}
// 写入数据库
const newBaseDict = await ctx.sequelize.models.BaseDict.create({
atomModel: atomModelId,
baseDictName,
baseDictFather,
baseDictDescribe,
baseDictIdentify,
});
// 获取原始数据
const newBaseDictItem = newBaseDict.dataValues;
newBaseDictItem.children = [];
newBaseDictItem.delChildren = [];
// 压入原始全量字典列表缓存
RBP.atomAllList.push(newBaseDictItem);
// 压入原始正常字典列表缓存
RBP.atomNormalList.push(newBaseDictItem);
// 建立原始字典对象
RBP.atomObject[newBaseDictItem.baseDictId] = newBaseDictItem;
// 建立原始字典对象关系
RBP.atomObject['0'].children.push(newBaseDictItem);
// 生成简化数据
const reduceData = {
atomModel: newBaseDictItem.atomModel,
baseDictId: newBaseDictItem.baseDictId,
baseDictName: newBaseDictItem.baseDictName,
baseDictIdentify: newBaseDictItem.baseDictIdentify,
baseDictDescribe: newBaseDictItem.baseDictDescribe,
baseDictFather: newBaseDictItem.baseDictFather,
children: [],
delChildren: [],
};
// 建立简化字典对象
RBP.reduceObject[newBaseDictItem.baseDictId] = reduceData;
// 建立简化字典对象关系
RBP.reduceObject['0'].children.push(reduceData);
if (
!Object.keys(RBP.atomModelObject).includes(atomModelId.toString())
) {
// 判断缓存是否存在元分类/模型对象
// 建立元分类字典缓存对象
RBP.atomModelObject[atomModelId] = {
baseDictTree: [],
reduceBaseDictTree: [],
};
}
// 分别压入精简原始字典对象到根节点树
RBP.atomModelObject[atomModelId].baseDictTree.push(newBaseDictItem);
RBP.atomModelObject[atomModelId].baseDictTree.push(reduceData);
return (ctx.body = {
message: '添加字典项成功',
data: newBaseDictItem,
});
} else {
// 子节点
// 判断父节点是否存在
if (
!RBP.atomObject[baseDictFather] ||
(RBP.atomObject[baseDictFather] &&
RBP.atomObject[baseDictFather].isDelete)
) {
return ctx.throw(400, { e: '不存在父节点' });
}
// 获取根节点元分类/模型ID
const rootAtomModelId = getRootAtomModelId(baseDictFather);
if (atomModelId != undefined && atomModelId != rootAtomModelId) {
return ctx.throw(400, {
e: '目标元分类/模型与根字典元分类/模型不匹配',
});
}
// 查同级节点重名
const check = checkTargetChildrenDictName(baseDictFather, baseDictName);
if (check != -1) {
return ctx.throw(400, { e: '该根字典项在目标字典下重名' });
}
// 写入数据库
const newBaseDict = await ctx.sequelize.models.BaseDict.create({
atomModel: atomModelId,
baseDictName,
baseDictFather,
baseDictDescribe,
baseDictIdentify,
});
// 获取原始数据
const newBaseDictItem = newBaseDict.dataValues;
newBaseDictItem.children = [];
newBaseDictItem.delChildren = [];
// 压入原始全量字典列表缓存
RBP.atomAllList.push(newBaseDictItem);
// 压入原始正常字典列表缓存
RBP.atomNormalList.push(newBaseDictItem);
// 建立原始字典对象
RBP.atomObject[newBaseDictItem.baseDictId] = newBaseDictItem;
// 建立原始字典对象关系
RBP.atomObject[baseDictFather].children.push(newBaseDictItem);
// 生成简化数据
const reduceData = {
atomModel: newBaseDictItem.atomModel,
baseDictId: newBaseDictItem.baseDictId,
baseDictName: newBaseDictItem.baseDictName,
baseDictIdentify: newBaseDictItem.baseDictIdentify,
baseDictDescribe: newBaseDictItem.baseDictDescribe,
baseDictFather: newBaseDictItem.baseDictFather,
children: [],
delChildren: [],
};
// 建立简化字典对象
RBP.reduceObject[newBaseDictItem.baseDictId] = reduceData;
// 建立简化字典对象关系
RBP.reduceObject[baseDictFather].children.push(reduceData);
// 检查一下AtomModelObject
// console.log(JSON.stringify(RBP.atomModelObject[atomModelId].baseDictTree,null,4));
// console.log(JSON.stringify(RBP.atomModelObject[atomModelId].reduceBaseDictTree, null, 4));
return (ctx.body = {
message: '添加字典项成功',
data: newBaseDictItem,
});
}
ctx.body = 5
});
// @ 编辑字典项
baseDict.post('/editBaseDictItem', async (ctx, next) => {
const data = ctx.request.body;
const verif = EditBaseDictItemDTO(data);
const verif = EditBaseDictItemDTO(ctx.request.body);
if (!verif.status) {
ctx.throw(400, { e: verif.error.map((i) => i.message) });
return;
return ctx.throw(400, { e: verif.error.map((i) => i.message) });
}
const baseDictId = ctx.request.body.baseDictId;
const baseDictName = ctx.request.body.baseDictName;
const baseDictDescribe = ctx.request.body.baseDictDescribe;
const baseDictIdentify = ctx.request.body.baseDictIdentify;
const RBP = resourceCache.baseDictPool;
// 检查字典项是否存在
if (!(RBP.atomObject[baseDictId] && !RBP.atomObject[baseDictId].isDelete)) {
return ctx.throw(400, { e: '待修改的字典项不存在' });
}
// 查重名
const baseDictFather = RBP.atomObject[baseDictId].baseDictFather;
if (baseDictFather == 0) {
const check = checkRootDictName(
baseDictName,
RBP.atomObject[baseDictId].atomModel,
);
if (
check != -1 &&
RBP.atomObject[baseDictFather].children[check].baseDictId !=
baseDictId
) {
return ctx.throw(400, { e: '待修改的字典项在目标字典下重名' });
}
} else {
const check = checkTargetChildrenDictName(baseDictFather, baseDictName);
if (
check != -1 &&
RBP.atomObject[baseDictFather].children[check].baseDictId !=
baseDictId
) {
return ctx.throw(400, { e: '待修改的字典项在目标字典下重名' });
}
}
ctx.body = 6
// 更新原始对象字典
RBP.atomObject[baseDictId].baseDictId = baseDictId;
RBP.atomObject[baseDictId].baseDictName = baseDictName;
RBP.atomObject[baseDictId].baseDictDescribe = baseDictDescribe;
RBP.atomObject[baseDictId].baseDictIdentify = baseDictIdentify;
// 更新精简对象字典
RBP.reduceObject[baseDictId].baseDictId = baseDictId;
RBP.reduceObject[baseDictId].baseDictName = baseDictName;
RBP.reduceObject[baseDictId].baseDictDescribe = baseDictDescribe;
RBP.reduceObject[baseDictId].baseDictIdentify = baseDictIdentify;
// 检查一下AtomModelObject
// console.log(JSON.stringify(RBP.atomModelObject[RBP.atomObject[baseDictId].atomModel].baseDictTree,null,4));
// console.log(JSON.stringify(RBP.atomModelObject[RBP.atomObject[baseDictId].atomModel].reduceBaseDictTree, null, 4));
ctx.body = {
message: '字典项更新成功',
};
await next();
await ctx.sequelize.models.BaseDict.update(
{
baseDictName,
baseDictDescribe,
baseDictIdentify,
},
{ where: { baseDictId } },
);
});
export default baseDict;
// 查重根节点的字典名字
function checkRootDictName(baseDictName, atomModelId) {
const RBP = resourceCache.baseDictPool;
const normalRootList = RBP.reduceObject[0].children;
for (let i = 0; i < normalRootList.length; i++) {
if (
normalRootList[i].baseDictName == baseDictName &&
normalRootList[i].atomModel == atomModelId
) {
return i;
}
}
return -1;
}
// 查重目标节点的子节点名字
function checkTargetChildrenDictName(baseDictFather, baseDictName) {
const RBP = resourceCache.baseDictPool;
const targetList = RBP.atomObject[baseDictFather].children;
for (let i = 0; i < targetList.length; i++) {
if (targetList[i].baseDictName == baseDictName) {
return i;
}
}
return -1;
}
// 获取字典项的根节点上的元分类/模型ID
function getRootAtomModelId(baseDictFather) {
const fatherNode = resourceCache.baseDictPool.atomObject[baseDictFather];
if (fatherNode.baseDictFather == 0) {
return fatherNode.atomModel;
} else {
return getRootAtomModelId(fatherNode.baseDictFather);
}
}
// 查字典项下所有的子节点id
function getAllChildrenBaseDictId(baseDictId) {
const baseDictIdList = [];
for (
let i = 0;
i < resourceCache.baseDictPool.atomObject[baseDictId].children.length;
i++
) {
if (
resourceCache.baseDictPool.atomObject[baseDictId].children[i]
.children.length > 0
) {
baseDictIdList.push(
...getAllChildrenBaseDictId(
resourceCache.baseDictPool.atomObject[baseDictId].children[
i
].baseDictId,
),
);
}
baseDictIdList.push(
resourceCache.baseDictPool.atomObject[baseDictId].children[i]
.baseDictId,
);
}
return baseDictIdList;
}
// 把children移动至delChildren
function moveChildrenToDelChildren(obj) {
if (obj.children.length > 0) {
for (let i = 0; i < obj.children.length; i++) {
moveChildrenToDelChildren(obj.children[i]);
}
}
obj.delChildren.push(...obj.children);
obj.delChildren.sort((a, b) => a.baseDictId - b.baseDictId);
obj.children = [];
}

@ -0,0 +1,15 @@
// | ------------------------------------------------------------
// | @版本: version 0.1
// | @创建人: 【Nie-x7129】
// | @E-mail: x71291@outlook.com
// | @所在项目: graphResource2
// | @文件描述: slice.js -
// | @创建时间: 2023-12-03 01:43
// | @更新时间: 2023-12-03 01:43
// | @修改记录:
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
// | =
// | ------------------------------------------------------------
console.log([1, 2, 3].slice(1))
Loading…
Cancel
Save