feat: remove MultipleKeywordsInput plugin and associated files

This commit is contained in:
Zeke Zhang 2025-04-17 09:44:45 +08:00
parent 56bc058389
commit a6d3c5b70e
18 changed files with 0 additions and 599 deletions

View File

@ -1 +0,0 @@
# @nocobase/plugin-filter-operator-multiple-keywords

View File

@ -1,2 +0,0 @@
export * from './dist/client';
export { default } from './dist/client';

View File

@ -1 +0,0 @@
module.exports = require('./dist/client/index.js');

View File

@ -1,22 +0,0 @@
{
"name": "@nocobase/plugin-filter-operator-multiple-keywords",
"version": "1.7.0-beta.18",
"main": "dist/server/index.js",
"displayName": "Multiple keywords",
"displayName.zh-CN": "多关键词筛选",
"description": "Support for filtering multiple keywords in a single line text field.",
"description.zh-CN": "单行文本字段支持多关键词筛选。",
"homepage": "https://docs.nocobase.com/handbook/",
"homepage.zh-CN": "https://docs-cn.nocobase.com/handbook/",
"keywords": [
"Multiple keywords"
],
"dependencies": {
"xlsx": "0.18.5"
},
"peerDependencies": {
"@nocobase/client": "1.x",
"@nocobase/server": "1.x",
"@nocobase/test": "1.x"
}
}

View File

@ -1,2 +0,0 @@
export * from './dist/server';
export { default } from './dist/server';

View File

@ -1 +0,0 @@
module.exports = require('./dist/server/index.js');

View File

@ -1,201 +0,0 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { RemoteSelect, useCollection } from '@nocobase/client';
import React, { FC, useRef, useState } from 'react';
import { Button, Space, Modal, message, Select, Alert } from 'antd';
import { useFieldSchema } from '@formily/react';
import * as XLSX from 'xlsx';
import { useT } from './locale';
export const MultipleKeywordsInput: FC<any> = (props) => {
const collection = useCollection();
const fieldSchema = useFieldSchema();
const fileInputRef = useRef<HTMLInputElement>(null);
const [importLoading, setImportLoading] = useState(false);
const [columnModal, setColumnModal] = useState(false);
const [columns, setColumns] = useState<string[]>([]);
const [selectedColumns, setSelectedColumns] = useState<string[]>([]);
const [excelData, setExcelData] = useState<any[]>([]);
const t = useT();
const handleImportButtonClick = () => {
fileInputRef.current?.click();
};
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
try {
setImportLoading(true);
// 读取 Excel 文件
const data = await readExcel(file);
if (data.length === 0) {
message.error('Excel 文件为空');
setImportLoading(false);
return;
}
// 提取所有列名
const extractedColumns = Object.keys(data[0]);
setColumns(extractedColumns);
setExcelData(data);
// 如果只有一列,直接导入
if (extractedColumns.length === 1) {
const keywords = extractKeywordsFromColumn(data, extractedColumns[0]);
handleImportKeywords(keywords);
} else {
// 如果有多列,打开选择对话框
setColumnModal(true);
}
} catch (error) {
console.error('解析 Excel 文件出错:', error);
message.error('解析 Excel 文件失败');
} finally {
setImportLoading(false);
// 清空文件输入,以便下次选择同一文件时仍能触发 change 事件
event.target.value = '';
}
}
};
// 读取 Excel 文件内容
const readExcel = (file: File): Promise<any[]> => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
try {
const data = e.target?.result;
const workbook = XLSX.read(data, { type: 'binary' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
const jsonData = XLSX.utils.sheet_to_json(worksheet);
resolve(jsonData);
} catch (error) {
reject(error);
}
};
reader.onerror = (error) => reject(error);
reader.readAsBinaryString(file);
});
};
// 从指定列提取关键词
const extractKeywordsFromColumn = (data: any[], columnName: string): string => {
return data
.map((row) => row[columnName])
.filter((value) => value !== undefined && value !== null && value !== '')
.join(',');
};
// 从多个列提取关键词
const extractKeywordsFromColumns = (data: any[], columnNames: string[]): string => {
const keywordSet = new Set<string>();
data.forEach((row) => {
columnNames.forEach((column) => {
const value = row[column];
if (value !== undefined && value !== null && value !== '') {
keywordSet.add(value.toString());
}
});
});
return Array.from(keywordSet).join(',');
};
// 处理导入关键词到输入框
const handleImportKeywords = (keywords: string) => {
if (!keywords) {
message.warning('未找到有效关键词');
return;
}
// 将关键词设置到输入框
if (props.onChange) {
const keywordArray = keywords.split(',').filter(Boolean);
props.onChange(keywordArray);
message.success(`成功导入 ${keywordArray.length} 个关键词`);
}
};
// 处理列选择确认
const handleColumnSelectConfirm = () => {
if (selectedColumns.length === 0) {
message.warning('请至少选择一列');
return;
}
const keywords = extractKeywordsFromColumns(excelData, selectedColumns);
handleImportKeywords(keywords);
setColumnModal(false);
};
return (
<>
<Space.Compact block>
<RemoteSelect
mode="tags"
placeholder="支持输入多个关键词,通过逗号或者换行符分割"
tokenSeparators={[',', '\n', '']}
fieldNames={{
label: fieldSchema.name as string,
value: fieldSchema.name as string,
}}
service={{
resource: collection.name,
action: 'list',
}}
{...props}
/>
<Button onClick={handleImportButtonClick} loading={importLoading}>
Excel
</Button>
</Space.Compact>
<input
type="file"
ref={fileInputRef}
style={{ display: 'none' }}
accept=".xlsx,.xls"
onChange={handleFileChange}
/>
{/* 列选择对话框 */}
<Modal
title="选择要导入的 Excel 列"
open={columnModal}
onOk={handleColumnSelectConfirm}
onCancel={() => setColumnModal(false)}
okText="确认"
cancelText="取消"
>
<Alert
type="info"
style={{ marginBottom: '10px', whiteSpace: 'pre-line', padding: '4px 8px' }}
description={t('tips')}
/>
<Select
mode="multiple"
value={selectedColumns}
onChange={(values) => setSelectedColumns(values)}
style={{ width: '100%' }}
placeholder="请选择要导入的列"
>
{columns.map((column) => (
<Select.Option key={column} value={column}>
{column}
</Select.Option>
))}
</Select>
</Modal>
</>
);
};

View File

@ -1,249 +0,0 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
// CSS modules
type CSSModuleClasses = { readonly [key: string]: string };
declare module '*.module.css' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.scss' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.sass' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.less' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.styl' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.stylus' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.pcss' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.sss' {
const classes: CSSModuleClasses;
export default classes;
}
// CSS
declare module '*.css' { }
declare module '*.scss' { }
declare module '*.sass' { }
declare module '*.less' { }
declare module '*.styl' { }
declare module '*.stylus' { }
declare module '*.pcss' { }
declare module '*.sss' { }
// Built-in asset types
// see `src/node/constants.ts`
// images
declare module '*.apng' {
const src: string;
export default src;
}
declare module '*.png' {
const src: string;
export default src;
}
declare module '*.jpg' {
const src: string;
export default src;
}
declare module '*.jpeg' {
const src: string;
export default src;
}
declare module '*.jfif' {
const src: string;
export default src;
}
declare module '*.pjpeg' {
const src: string;
export default src;
}
declare module '*.pjp' {
const src: string;
export default src;
}
declare module '*.gif' {
const src: string;
export default src;
}
declare module '*.svg' {
const src: string;
export default src;
}
declare module '*.ico' {
const src: string;
export default src;
}
declare module '*.webp' {
const src: string;
export default src;
}
declare module '*.avif' {
const src: string;
export default src;
}
// media
declare module '*.mp4' {
const src: string;
export default src;
}
declare module '*.webm' {
const src: string;
export default src;
}
declare module '*.ogg' {
const src: string;
export default src;
}
declare module '*.mp3' {
const src: string;
export default src;
}
declare module '*.wav' {
const src: string;
export default src;
}
declare module '*.flac' {
const src: string;
export default src;
}
declare module '*.aac' {
const src: string;
export default src;
}
declare module '*.opus' {
const src: string;
export default src;
}
declare module '*.mov' {
const src: string;
export default src;
}
declare module '*.m4a' {
const src: string;
export default src;
}
declare module '*.vtt' {
const src: string;
export default src;
}
// fonts
declare module '*.woff' {
const src: string;
export default src;
}
declare module '*.woff2' {
const src: string;
export default src;
}
declare module '*.eot' {
const src: string;
export default src;
}
declare module '*.ttf' {
const src: string;
export default src;
}
declare module '*.otf' {
const src: string;
export default src;
}
// other
declare module '*.webmanifest' {
const src: string;
export default src;
}
declare module '*.pdf' {
const src: string;
export default src;
}
declare module '*.txt' {
const src: string;
export default src;
}
// wasm?init
declare module '*.wasm?init' {
const initWasm: (options?: WebAssembly.Imports) => Promise<WebAssembly.Instance>;
export default initWasm;
}
// web worker
declare module '*?worker' {
const workerConstructor: {
new(options?: { name?: string }): Worker;
};
export default workerConstructor;
}
declare module '*?worker&inline' {
const workerConstructor: {
new(options?: { name?: string }): Worker;
};
export default workerConstructor;
}
declare module '*?worker&url' {
const src: string;
export default src;
}
declare module '*?sharedworker' {
const sharedWorkerConstructor: {
new(options?: { name?: string }): SharedWorker;
};
export default sharedWorkerConstructor;
}
declare module '*?sharedworker&inline' {
const sharedWorkerConstructor: {
new(options?: { name?: string }): SharedWorker;
};
export default sharedWorkerConstructor;
}
declare module '*?sharedworker&url' {
const src: string;
export default src;
}
declare module '*?raw' {
const src: string;
export default src;
}
declare module '*?url' {
const src: string;
export default src;
}
declare module '*?inline' {
const src: string;
export default src;
}

View File

@ -1,43 +0,0 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Plugin } from '@nocobase/client';
import { MultipleKeywordsInput } from './MultipleKeywordsInput';
export class PluginFilterOperatorMultipleKeywordsClient extends Plugin {
async afterAdd() {
// await this.app.pm.add()
}
async beforeLoad() {}
// You can get and modify the app instance here
async load() {
this.app.addFieldInterfaceOperator('input', {
label: '{{t("等于任意一个")}}',
value: '$in',
schema: {
'x-component': 'MultipleKeywordsInput',
},
});
this.app.addFieldInterfaceOperator('input', {
label: '{{t("不等于任意一个")}}',
value: '$notIn',
schema: {
'x-component': 'MultipleKeywordsInput',
},
});
this.app.addComponents({
MultipleKeywordsInput,
});
}
}
export default PluginFilterOperatorMultipleKeywordsClient;

View File

@ -1,21 +0,0 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
// @ts-ignore
import pkg from './../../package.json';
import { useApp } from '@nocobase/client';
export function useT() {
const app = useApp();
return (str: string) => app.i18n.t(str, { ns: [pkg.name, 'client'] });
}
export function tStr(key: string) {
return `{{t(${JSON.stringify(key)}, { ns: ['${pkg.name}', 'client'], nsMode: 'fallback' })}}`;
}

View File

@ -1,11 +0,0 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
export * from './server';
export { default } from './server';

View File

@ -1,3 +0,0 @@
{
"tips": "选择单列的效果:将导入该列的所有非空值作为关键词\n选择多列的效果将合并多个列的非空值作为关键词重复值将被去除"
}

View File

@ -1,10 +0,0 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
export { default } from './plugin';

View File

@ -1,28 +0,0 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { Plugin } from '@nocobase/server';
export class PluginFilterOperatorMultipleKeywordsServer extends Plugin {
async afterAdd() {}
async beforeLoad() {}
async load() {}
async install() {}
async afterEnable() {}
async afterDisable() {}
async remove() {}
}
export default PluginFilterOperatorMultipleKeywordsServer;