Compare commits

...

11 Commits

Author SHA1 Message Date
whyour 79b342d1d2 更新版本 v2.15.11 2023-03-31 22:38:32 +08:00
whyour 20b0d75b0d 修改 pnpm 版本 2023-03-30 23:20:38 +08:00
whyour c89724906e 修复定时任务表头样式 2023-03-23 22:19:48 +08:00
whyour c3a548ece3 修改定时任务列表滚动 2023-03-22 22:30:47 +08:00
whyour b431e39f8f 修复系统设置中登录日志样式 2023-03-20 23:23:03 +08:00
whyour 710746809b 修复删除视图筛选条件 2023-03-20 23:00:13 +08:00
whyour 8a225e9beb 修复视图筛选条件样式 2023-03-20 18:03:09 +08:00
whyour a5ecb204b2 修复 python Server酱推送 2023-03-19 22:54:50 +08:00
whyour f1f009da3b 禁止手机浏览器下拉刷新 2023-03-19 15:15:01 +08:00
whyour 7291098f98 修复手机页面滚动 2023-03-19 15:11:28 +08:00
whyour 666545ff03 修改初始化依赖安装逻辑 2023-03-18 22:26:29 +08:00
15 changed files with 210 additions and 217 deletions
+2 -2
View File
@@ -45,7 +45,7 @@ jobs:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: latest
version: 7
- uses: actions/setup-node@v3
with:
@@ -99,7 +99,7 @@ jobs:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: latest
version: 7
- uses: actions/setup-node@v3
with:
cache: 'pnpm'
+7 -10
View File
@@ -4,8 +4,7 @@ import { Container } from 'typedi';
import { Crontab, CrontabModel, CrontabStatus } from '../data/cron';
import CronService from '../services/cron';
import EnvService from '../services/env';
import groupBy from 'lodash/groupBy';
import { DependenceModel } from '../data/dependence';
import { DependenceModel, DependenceStatus } from '../data/dependence';
import { Op } from 'sequelize';
import config from '../config';
import { CrontabViewModel, CronViewType } from '../data/cronView';
@@ -42,16 +41,14 @@ export default async () => {
order: [['type', 'DESC']],
raw: true,
}).then(async (docs) => {
const groups = groupBy(docs, 'type');
const keys = Object.keys(groups).sort((a, b) => parseInt(b) - parseInt(a));
for (const key of keys) {
const group = groups[key];
const depIds = group.map((x) => x.id);
await dependenceService.reInstall(depIds as number[]);
}
await DependenceModel.update(
{ status: DependenceStatus.installing, log: [] },
{ where: { id: docs.map((x) => x.id!) } },
);
dependenceService.installDependenceOneByOne(docs);
});
// 初始化时执行一次所有的ql repo 任务
// 初始化时执行一次所有的 ql repo 任务
CrontabModel.findAll({
where: {
isDisabled: { [Op.ne]: 1 },
+1 -1
View File
@@ -99,7 +99,7 @@ export default class DependenceService {
}
}
private installDependenceOneByOne(
public installDependenceOneByOne(
docs: Dependence[],
isInstall: boolean = true,
force: boolean = false,
+1
View File
@@ -147,6 +147,7 @@
"typescript": "4.8.4",
"umi-request": "^1.4.0",
"vh-check": "^2.0.5",
"virtualizedtableforantd4": "1.3.0",
"webpack": "^5.70.0",
"yorkie": "^2.0.0"
}
+22 -1
View File
@@ -90,6 +90,7 @@ specifiers:
umi-request: ^1.4.0
uuid: ^8.3.2
vh-check: ^2.0.5
virtualizedtableforantd4: 1.3.0
webpack: ^5.70.0
winston: ^3.6.0
yargs: ^17.3.1
@@ -189,6 +190,7 @@ devDependencies:
typescript: 4.8.4
umi-request: 1.4.0
vh-check: 2.0.5
virtualizedtableforantd4: 1.3.0_eyanc6viuzknyw5lsn6lba32mq
webpack: 5.75.0
yorkie: 2.0.0
@@ -13564,7 +13566,7 @@ packages:
/rxjs/7.8.0:
resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==}
dependencies:
tslib: 2.4.1
tslib: 2.5.0
dev: true
/safe-buffer/5.1.2:
@@ -15195,6 +15197,25 @@ packages:
resolution: {integrity: sha512-vHtIYWt9uLl2P2tLlatVpMwv9+ezuJCtMNjUVIpzd5Pa/dJXN8AtqkKmVRcNSlmXyCjkCkbMQX/Vs9axmdlfgg==}
dev: true
/virtualizedtableforantd4/1.3.0_eyanc6viuzknyw5lsn6lba32mq:
resolution: {integrity: sha512-V7y4/yFMo1xr/20Q3up6wPNPe9K5xvkPuj/LnSouDzM7pxWOwdvp/qndr86BISpH2OIzfAoZjSIivKktOXP4dQ==}
peerDependencies:
antd: ^4.0.0 || ^5.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || 18
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || 18
peerDependenciesMeta:
antd:
optional: true
react:
optional: true
react-dom:
optional: true
dependencies:
antd: 4.24.8_biqbaboplfbrettd7655fr4n2y
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
dev: true
/vite/4.1.4_uakuilq6iygkg5ll5cv37w4i7m:
resolution: {integrity: sha512-3knk/HsbSTKEin43zHu7jTwYWv81f8kgAL99G5NWBcA1LKvtvcVAC4JjBH1arBunO9kQka+1oGbrMKOjk4ZrBg==}
engines: {node: ^14.18.0 || >=16.0.0}
+28 -18
View File
@@ -164,7 +164,8 @@ def dingding_bot(title: str, content: str) -> None:
timestamp = str(round(time.time() * 1000))
secret_enc = push_config.get("DD_BOT_SECRET").encode("utf-8")
string_to_sign = "{}\n{}".format(timestamp, push_config.get("DD_BOT_SECRET"))
string_to_sign = "{}\n{}".format(
timestamp, push_config.get("DD_BOT_SECRET"))
string_to_sign_enc = string_to_sign.encode("utf-8")
hmac_code = hmac.new(
secret_enc, string_to_sign_enc, digestmod=hashlib.sha256
@@ -220,7 +221,7 @@ def go_cqhttp(title: str, content: str) -> None:
print("go-cqhttp 推送失败!")
def gotify(title:str,content:str) -> None:
def gotify(title: str, content: str) -> None:
"""
使用 gotify 推送消息。
"""
@@ -230,8 +231,9 @@ def gotify(title:str,content:str) -> None:
print("gotify 服务启动")
url = f'{push_config.get("GOTIFY_URL")}/message?token={push_config.get("GOTIFY_TOKEN")}'
data = {"title": title,"message": content,"priority": push_config.get("GOTIFY_PRIORITY")}
response = requests.post(url,data=data).json()
data = {"title": title, "message": content,
"priority": push_config.get("GOTIFY_PRIORITY")}
response = requests.post(url, data=data).json()
if response.get("id"):
print("gotify 推送成功!")
@@ -269,10 +271,10 @@ def serverJ(title: str, content: str) -> None:
print("serverJ 服务启动")
data = {"text": title, "desp": content.replace("\n", "\n\n")}
if push_config.get("PUSH_KEY").index("SCT") != -1:
if push_config.get("PUSH_KEY").find("SCT") != -1:
url = f'https://sctapi.ftqq.com/{push_config.get("PUSH_KEY")}.send'
else:
url = f'https://sc.ftqq.com/${push_config.get("PUSH_KEY")}.send'
url = f'https://sc.ftqq.com/{push_config.get("PUSH_KEY")}.send'
response = requests.post(url, data=data).json()
if response.get("errno") == 0 or response.get("code") == 0:
@@ -289,7 +291,8 @@ def pushdeer(title: str, content: str) -> None:
print("PushDeer 服务的 DEER_KEY 未设置!!\n取消推送")
return
print("PushDeer 服务启动")
data = {"text": title, "desp": content, "type": "markdown", "pushkey": push_config.get("DEER_KEY")}
data = {"text": title, "desp": content, "type": "markdown",
"pushkey": push_config.get("DEER_KEY")}
url = 'https://api2.pushdeer.com/message/push'
if push_config.get("DEER_URL"):
url = push_config.get("DEER_URL")
@@ -320,7 +323,6 @@ def chat(title: str, content: str) -> None:
print("Chat 推送失败!错误信息:", response)
def pushplus_bot(title: str, content: str) -> None:
"""
通过 push+ 推送消息。
@@ -348,7 +350,8 @@ def pushplus_bot(title: str, content: str) -> None:
url_old = "http://pushplus.hxtrip.com/send"
headers["Accept"] = "application/json"
response = requests.post(url=url_old, data=body, headers=headers).json()
response = requests.post(
url=url_old, data=body, headers=headers).json()
if response["code"] == 200:
print("PUSHPLUS(hxtrip) 推送成功!")
@@ -367,7 +370,8 @@ def qmsg_bot(title: str, content: str) -> None:
print("qmsg 服务启动")
url = f'https://qmsg.zendee.cn/{push_config.get("QMSG_TYPE")}/{push_config.get("QMSG_KEY")}'
payload = {"msg": f'{title}\n\n{content.replace("----", "-")}'.encode("utf-8")}
payload = {
"msg": f'{title}\n\n{content.replace("----", "-")}'.encode("utf-8")}
response = requests.post(url=url, params=payload).json()
if response["code"] == 0:
@@ -553,14 +557,14 @@ def aibotk(title: str, content: str) -> None:
data = {
"apiKey": push_config.get("AIBOTK_KEY"),
"roomName": push_config.get("AIBOTK_NAME"),
"message": {"type": 1, "content": f'【青龙快讯】\n\n${title}\n${content}' }
"message": {"type": 1, "content": f'【青龙快讯】\n\n{title}\n{content}'}
}
else:
url = "https://api-bot.aibotk.com/openapi/v1/chat/contact"
data = {
"apiKey": push_config.get("AIBOTK_KEY"),
"name": push_config.get("AIBOTK_NAME"),
"message": {"type": 1, "content": f'【青龙快讯】\n\n${title}\n${content}' }
"message": {"type": 1, "content": f'【青龙快讯】\n\n{title}\n{content}'}
}
body = json.dumps(data).encode(encoding="utf-8")
headers = {"Content-Type": "application/json"}
@@ -582,14 +586,19 @@ def smtp(title: str, content: str) -> None:
print("SMTP 邮件 服务启动")
message = MIMEText(content, 'plain', 'utf-8')
message['From'] = formataddr((Header(push_config.get("SMTP_NAME"), 'utf-8').encode(), push_config.get("SMTP_EMAIL")))
message['To'] = formataddr((Header(push_config.get("SMTP_NAME"), 'utf-8').encode(), push_config.get("SMTP_EMAIL")))
message['From'] = formataddr((Header(push_config.get(
"SMTP_NAME"), 'utf-8').encode(), push_config.get("SMTP_EMAIL")))
message['To'] = formataddr((Header(push_config.get(
"SMTP_NAME"), 'utf-8').encode(), push_config.get("SMTP_EMAIL")))
message['Subject'] = Header(title, 'utf-8')
try:
smtp_server = smtplib.SMTP_SSL(push_config.get("SMTP_SERVER")) if push_config.get("SMTP_SSL") == 'true' else smtplib.SMTP(push_config.get("SMTP_SERVER"))
smtp_server.login(push_config.get("SMTP_EMAIL"), push_config.get("SMTP_PASSWORD"))
smtp_server.sendmail(push_config.get("SMTP_EMAIL"), push_config.get("SMTP_EMAIL"), message.as_bytes())
smtp_server = smtplib.SMTP_SSL(push_config.get("SMTP_SERVER")) if push_config.get(
"SMTP_SSL") == 'true' else smtplib.SMTP(push_config.get("SMTP_SERVER"))
smtp_server.login(push_config.get("SMTP_EMAIL"),
push_config.get("SMTP_PASSWORD"))
smtp_server.sendmail(push_config.get("SMTP_EMAIL"),
push_config.get("SMTP_EMAIL"), message.as_bytes())
smtp_server.close()
print("SMTP 邮件 推送成功!")
except Exception as e:
@@ -660,7 +669,8 @@ def send(title: str, content: str) -> None:
content += "\n\n" + text
ts = [
threading.Thread(target=mode, args=(title, content), name=mode.__name__)
threading.Thread(target=mode, args=(
title, content), name=mode.__name__)
for mode in notify_function
]
[t.start() for t in ts]
+5 -1
View File
@@ -61,7 +61,11 @@ handle_log_path() {
format_params() {
time_format="%Y-%m-%d %H:%M:%S"
mtime_format="%Y-%m-%d %H:%M:%S.%3N"
if [[ $is_macos -eq 1 ]]; then
mtime_format=$time_format
else
mtime_format="%Y-%m-%d %H:%M:%S.%3N"
fi
timeoutCmd=""
if type timeout &>/dev/null; then
timeoutCmd="timeout --foreground -s 14 -k 10s $command_timeout_time "
+11
View File
@@ -9,9 +9,20 @@
url('../assets/fonts/SourceCodePro-Regular.ttf') format('truetype');
}
body {
// 禁止手机页面下拉刷新
overflow: hidden;
// 禁止手机页面弹簧效果
position: fixed;
top: 0;
left: 0;
}
#root {
height: 100vh;
height: calc(100vh - var(--vh-offset, 0px));
-webkit-overflow-scrolling: touch;
}
.ant-modal-body {
+8 -1
View File
@@ -155,7 +155,7 @@
.view-create-modal-sorts {
display: flex;
.ant-space-item:nth-child(2) {
.ant-space-item:nth-child(1) {
flex: 1;
}
}
@@ -177,6 +177,7 @@ tr.drop-over-upward td {
.view-filters-container.active {
.filter-item > div > .ant-form-item-control {
margin-left: 40px;
width: calc(100% - 40px);
}
}
@@ -191,3 +192,9 @@ tr.drop-over-upward td {
margin: -24px;
}
}
.crontab-wrapper {
tbody .ant-table-cell {
height: 69px !important;
}
}
+6 -28
View File
@@ -53,7 +53,7 @@ import { SharedContext } from '@/layouts';
import useTableScrollHeight from '@/hooks/useTableScrollHeight';
import { getCommandScript, parseCrontab } from '@/utils';
import { ColumnProps } from 'antd/lib/table';
import { VList } from '../../components/vlist';
import { useVT } from 'virtualizedtableforantd4';
const { Text, Paragraph } = Typography;
const { Search } = Input;
@@ -330,7 +330,6 @@ const Crontab = () => {
<Tooltip title={isPc ? '运行' : ''}>
<a
onClick={(e) => {
setReset(false);
e.stopPropagation();
runCron(record, index);
}}
@@ -343,7 +342,6 @@ const Crontab = () => {
<Tooltip title={isPc ? '停止' : ''}>
<a
onClick={(e) => {
setReset(false);
e.stopPropagation();
stopCron(record, index);
}}
@@ -355,7 +353,6 @@ const Crontab = () => {
<Tooltip title={isPc ? '日志' : ''}>
<a
onClick={(e) => {
setReset(false);
e.stopPropagation();
setLogCron({ ...record, timestamp: Date.now() });
}}
@@ -399,10 +396,6 @@ const Crontab = () => {
const [moreMenuActive, setMoreMenuActive] = useState(false);
const tableRef = useRef<any>();
const tableScrollHeight = useTableScrollHeight(tableRef);
const resetRef = useRef<boolean>(true);
const setReset = (v) => {
resetRef.current = v;
};
const goToScriptManager = (record: any) => {
const result = getCommandScript(record.command);
@@ -686,7 +679,6 @@ const Crontab = () => {
items: getMenuItems(record),
onClick: ({ key, domEvent }) => {
domEvent.stopPropagation();
setReset(false);
action(key, record, index);
},
}}
@@ -722,7 +714,6 @@ const Crontab = () => {
};
const onSearch = (value: string) => {
setReset(true);
setSearchText(value.trim());
};
@@ -750,10 +741,6 @@ const Crontab = () => {
setSelectedRowIds(selectedIds);
};
useEffect(() => {
setReset(false);
}, [selectedRowIds]);
const rowSelection = {
selectedRowKeys: selectedRowIds,
onChange: onSelectChange,
@@ -781,7 +768,6 @@ const Crontab = () => {
};
const operateCrons = (operationStatus: number) => {
setReset(false);
Modal.confirm({
title: `确认${OperationName[operationStatus]}`,
content: <>{OperationName[operationStatus]}</>,
@@ -808,7 +794,6 @@ const Crontab = () => {
sorter: SorterResult<any> | SorterResult<any>[],
) => {
const { current, pageSize } = pagination;
setReset(true);
setPageConf({
page: current as number,
size: pageSize as number,
@@ -923,21 +908,14 @@ const Crontab = () => {
const tabClick = (key: string) => {
const view = enabledCronViews.find((x) => x.id == key);
setSelectedRowIds([]);
setReset(true);
setPageConf({ ...pageConf, page: 1 });
setViewConf(view ? view : null);
};
const vComponents = useMemo(() => {
return VList({
height: tableScrollHeight,
reset: resetRef.current,
rowHeight: 69,
scrollTop: resetRef.current
? 0
: tableRef.current?.querySelector('.ant-table-body')?.scrollTop,
});
}, [tableScrollHeight, resetRef.current]);
const [vt] = useVT(
() => ({ scroll: { y: tableScrollHeight } }),
[tableScrollHeight],
);
return (
<PageContainer
@@ -1073,7 +1051,7 @@ const Crontab = () => {
rowSelection={rowSelection}
rowClassName={getRowClassName}
onChange={onPageChange}
components={vComponents}
components={isPhone ? undefined : vt}
/>
</div>
<CronLogModal
+84 -85
View File
@@ -70,6 +70,7 @@ const ViewCreateModal = ({
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [filterRelation, setFilterRelation] = useState<'and' | 'or'>('and');
const filtersValue = Form.useWatch('filters', form);
const handleOk = async (values: any) => {
setLoading(true);
@@ -126,7 +127,7 @@ const ViewCreateModal = ({
};
const typeElement = (
<Select>
<Select style={{ width: 80 }}>
{SORTTYPES.map((x) => (
<Select.Option key={x.name} value={x.value}>
{x.name}
@@ -204,7 +205,7 @@ const ViewCreateModal = ({
position: 'absolute',
top: '50%',
translate: '-50% -50%',
padding: '0 0 0 3px',
padding: '0 3px',
cursor: 'pointer',
}}
onClick={() => {
@@ -221,9 +222,9 @@ const ViewCreateModal = ({
</div>
)}
<div>
{fields.map(({ key, name, ...restField }, index) => (
{fields.map(({ key, name, ...restField }) => (
<Form.Item
label={index === 0 ? '筛选条件' : ''}
label={name === 0 ? '筛选条件' : ''}
key={key}
style={{ marginBottom: 0 }}
required
@@ -232,9 +233,6 @@ const ViewCreateModal = ({
<Space
className="view-create-modal-filters"
align="baseline"
style={
fields.length > 1 ? { width: 'calc(100% - 40px)' } : {}
}
>
<Form.Item
{...restField}
@@ -251,55 +249,18 @@ const ViewCreateModal = ({
{operationElement}
</Form.Item>
<Form.Item
noStyle
shouldUpdate={(prevValues, nextValues) => {
const preOperation =
EOperation[
get(prevValues, ['filters', name, 'operation'])
];
const nextOperation =
EOperation[
get(nextValues, ['filters', name, 'operation'])
];
const flag = preOperation !== nextOperation;
if (flag) {
form.setFieldValue(
['filters', name, 'value'],
nextOperation === 'select' ? [] : '',
);
}
return flag;
}}
{...restField}
name={[name, 'value']}
rules={[{ required: true, message: '请输入内容' }]}
>
{() => {
const property = form.getFieldValue([
'filters',
index,
'property',
]) as 'status';
const operate = form.getFieldValue([
'filters',
name,
'operation',
]);
return (
<Form.Item
{...restField}
name={[name, 'value']}
rules={[
{ required: true, message: '请输入内容' },
]}
>
{EOperation[operate] === 'select' ? (
statusElement(property)
) : (
<Input placeholder="请输入内容" />
)}
</Form.Item>
);
}}
{EOperation[filtersValue[name]['operation']] ===
'select' ? (
statusElement(filtersValue[name]['property'])
) : (
<Input placeholder="请输入内容" />
)}
</Form.Item>
{index !== 0 && (
{name !== 0 && (
<MinusCircleOutlined onClick={() => remove(name)} />
)}
</Space>
@@ -321,39 +282,77 @@ const ViewCreateModal = ({
</Form.List>
<Form.List name="sorts">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }, index) => (
<Form.Item
label={index === 0 ? '排序方式' : ''}
key={key}
style={{ marginBottom: 0 }}
<div
style={{ position: 'relative' }}
className={`view-filters-container ${
fields.length > 1 ? 'active' : ''
}`}
>
{fields.length > 1 && (
<div
style={{
position: 'absolute',
width: 50,
borderRadius: 10,
border: '1px solid rgb(190, 220, 255)',
borderRight: 'none',
height: 56 * (fields.length - 1),
top: 46,
left: 15,
}}
>
<Space className="view-create-modal-sorts" align="baseline">
<Form.Item
{...restField}
name={[name, 'property']}
rules={[{ required: true }]}
>
{propertyElement(PROPERTIES, { width: 240 })}
</Form.Item>
<Form.Item
{...restField}
name={[name, 'type']}
rules={[{ required: true }]}
>
{typeElement}
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} />
</Space>
<Button
type="primary"
size="small"
style={{
position: 'absolute',
top: '50%',
translate: '-50% -50%',
padding: '0 3px',
cursor: 'pointer',
}}
>
<>
<span>{ViewFilterRelation[filterRelation]}</span>
</>
</Button>
</div>
)}
<div>
{fields.map(({ key, name, ...restField }) => (
<Form.Item
label={name === 0 ? '排序方式' : ''}
key={key}
style={{ marginBottom: 0 }}
className="filter-item"
>
<Space className="view-create-modal-sorts" align="baseline">
<Form.Item
{...restField}
name={[name, 'property']}
rules={[{ required: true }]}
>
{propertyElement(PROPERTIES)}
</Form.Item>
<Form.Item
{...restField}
name={[name, 'type']}
rules={[{ required: true }]}
>
{typeElement}
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} />
</Space>
</Form.Item>
))}
<Form.Item>
<a onClick={() => add({ property: 'command', type: 'ASC' })}>
<PlusOutlined />
</a>
</Form.Item>
))}
<Form.Item>
<a onClick={() => add({ property: 'command', type: 'ASC' })}>
<PlusOutlined />
</a>
</Form.Item>
</>
</div>
</div>
)}
</Form.List>
</Form>
+26 -52
View File
@@ -39,7 +39,7 @@ import { useOutletContext } from '@umijs/max';
import { SharedContext } from '@/layouts';
import useTableScrollHeight from '@/hooks/useTableScrollHeight';
import Copy from '../../components/copy';
import { VList } from '../../components/vlist';
import { useVT } from 'virtualizedtableforantd4';
const { Text } = Typography;
const { Search } = Input;
@@ -216,10 +216,6 @@ const Env = () => {
const [importLoading, setImportLoading] = useState(false);
const tableRef = useRef<any>();
const tableScrollHeight = useTableScrollHeight(tableRef, 59);
const resetRef = useRef<boolean>(true);
const setReset = (v) => {
resetRef.current = v;
};
const getEnvs = () => {
setLoading(true);
@@ -234,7 +230,6 @@ const Env = () => {
};
const enabledOrDisabledEnv = (record: any, index: number) => {
setReset(false);
Modal.confirm({
title: `确认${record.status === Status. ? '启用' : '禁用'}`,
content: (
@@ -280,19 +275,16 @@ const Env = () => {
};
const addEnv = () => {
setReset(false);
setEditedEnv(null as any);
setIsModalVisible(true);
};
const editEnv = (record: any, index: number) => {
setReset(false);
setEditedEnv(record);
setIsModalVisible(true);
};
const deleteEnv = (record: any, index: number) => {
setReset(false);
Modal.confirm({
title: '确认删除',
content: (
@@ -332,20 +324,13 @@ const Env = () => {
getEnvs();
};
const vComponents = useMemo(() => {
return VList({
height: tableScrollHeight!,
reset: resetRef.current,
rowHeight: 48,
scrollTop: resetRef.current
? 0
: tableRef.current?.querySelector('.ant-table-body')?.scrollTop,
});
}, [tableScrollHeight, resetRef.current]);
const [vt, setVT] = useVT(
() => ({ scroll: { y: tableScrollHeight } }),
[tableScrollHeight],
);
const DragableBodyRow = (props: any) => {
const DragableBodyRow = React.forwardRef((props: any, ref) => {
const { index, moveRow, className, style, ...restProps } = props;
const ref = useRef();
const [{ isOver, dropClassName }, drop] = useDrop({
accept: type,
collect: (monitor) => {
@@ -373,31 +358,27 @@ const Env = () => {
useEffect(() => {
drop(drag(ref));
}, [drag, drop]);
}, [ref]);
const components = useMemo(() => vComponents.body.row, []);
return (
<tr
ref={ref}
className={`${className}${isOver ? dropClassName : ''}`}
style={{ cursor: 'move', ...style }}
{...restProps}
/>
);
});
const tempProps = useMemo(() => {
return {
ref: ref,
className: `${className}${isOver ? dropClassName : ''}`,
style: { cursor: 'move', ...style },
...restProps,
};
}, [className, dropClassName, restProps, style, isOver]);
return <> {components(tempProps, ref)} </>;
};
const components = useMemo(() => {
return {
...vComponents,
body: {
...vComponents.body,
row: DragableBodyRow,
},
};
}, [vComponents]);
useEffect(
() =>
setVT({
body: {
row: DragableBodyRow,
},
}),
[],
);
const moveRow = useCallback(
(dragIndex: number, hoverIndex: number) => {
@@ -425,17 +406,12 @@ const Env = () => {
setSelectedRowIds(selectedIds);
};
useEffect(() => {
setReset(false);
}, [selectedRowIds]);
const rowSelection = {
selectedRowKeys: selectedRowIds,
onChange: onSelectChange,
};
const delEnvs = () => {
setReset(false);
Modal.confirm({
title: '确认删除',
content: <></>,
@@ -457,7 +433,6 @@ const Env = () => {
};
const operateEnvs = (operationStatus: number) => {
setReset(false);
Modal.confirm({
title: `确认${OperationName[operationStatus]}`,
content: <>{OperationName[operationStatus]}</>,
@@ -490,7 +465,6 @@ const Env = () => {
};
const onSearch = (value: string) => {
setReset(true);
setSearchText(value.trim());
};
@@ -607,7 +581,7 @@ const Env = () => {
rowKey="id"
size="middle"
scroll={{ x: 1000, y: tableScrollHeight }}
components={components}
components={vt}
loading={loading}
onRow={(record: any, index: number | undefined) => {
return {
-8
View File
@@ -27,11 +27,3 @@
}
}
}
.ql-setting-container {
.ant-tabs-content-holder {
max-height: calc(100vh - 114px);
max-height: calc(100vh - var(--vh-offset, 114px));
overflow-y: auto;
}
}
+1
View File
@@ -72,6 +72,7 @@ const LoginLog = ({ data }: any) => {
rowKey="id"
size="middle"
scroll={{ x: 768 }}
sticky
/>
</>
);
+8 -10
View File
@@ -1,11 +1,9 @@
version: 2.15.10
changeLogLink: https://t.me/jiao_long/365
version: 2.15.11
changeLogLink: https://t.me/jiao_long/366
changeLog: |
1. 增加 ipv6 自动检测
2. 修复订阅管理下载 http 协议文件
3. 修复日志删除逻辑
4. 修复自定义通知
5. 修复检查更新弹框逻辑
6. 修复 bark 推送声音,感谢 https://github.com/adams549659584
7. 修复 task 命令获取 token
8. 其他 bug 修复
1. 优化手机端操作,更丝滑
2. 修复 python Server酱 推送
3. 修改初始化依赖安装逻辑
4. 修复删除视图筛选条件
5. 修改定时任务和环境变量列表滚动
6. 其他优化