fix: optimize admin/write page content #815

This commit is contained in:
shuai
2024-07-12 11:13:12 +08:00
parent 2be1807b0f
commit a4960f09be
6 changed files with 187 additions and 86 deletions
+8 -6
View File
@@ -1747,19 +1747,21 @@ ui:
write:
page_title: Write
restrict_answer:
title: Restrict answer
title: Answer write
label: Each user can only write one answer for the same question
text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused."
text: "Turn off to allow users to write multiple answers to the same question, which may cause answers to be unfocused."
recommend_tags:
label: Recommend tags
text: "Please input tag slug above, one tag per line."
text: "Recommend tags will show in the dropdown list by default."
msg:
contain_reserved: "recommended tags cannot contain reserved tags"
required_tag:
title: Required tag
label: Set recommend tag as required
title: Set required tags
label: Set “Recommend tags” as required tags
text: "Every new question must have at least one recommend tag."
reserved_tags:
label: Reserved tags
text: "Reserved tags can only be added to a post by moderator."
text: "Reserved tags can only be used by moderator."
seo:
page_title: SEO
permalink:
+3 -3
View File
@@ -425,9 +425,9 @@ export interface AdminSettingsLegal {
export interface AdminSettingsWrite {
restrict_answer?: boolean;
recommend_tags?: string[];
required_tag?: string;
reserved_tags?: string[];
recommend_tags?: Tag[];
required_tag?: boolean;
reserved_tags?: Tag[];
}
export interface AdminSettingsSeo {
+3
View File
@@ -97,6 +97,9 @@ export const useEditor = ({
wordWrap: 'break-word',
wordBreak: 'break-all',
},
'.ͼ7, .ͼ6': {
textDecoration: 'none',
},
});
const startState = EditorState.create({
+11 -3
View File
@@ -41,6 +41,8 @@ interface IProps {
showRequiredTag?: boolean;
autoFocus?: boolean;
isInvalid?: boolean;
tagStyleMode?: 'default' | 'simple';
formText?: string;
errMsg?: string;
}
@@ -55,6 +57,8 @@ const TagSelector: FC<IProps> = ({
showRequiredTag = false,
autoFocus = false,
isInvalid = false,
formText = '',
tagStyleMode = 'default',
errMsg = '',
}) => {
const containerRef = useRef<HTMLDivElement>(null);
@@ -366,8 +370,12 @@ const TagSelector: FC<IProps> = ({
key={item.slug_name}
className={classNames(
'badge-tag rounded-1 m-1 flex-shrink-0',
item.reserved && 'badge-tag-reserved',
item.recommend && 'badge-tag-required',
tagStyleMode === 'default' &&
item.reserved &&
'badge-tag-reserved',
tagStyleMode === 'default' &&
item.recommend &&
'badge-tag-required',
index === repeatIndex && 'bg-fade-out',
)}>
{item.display_name}
@@ -435,7 +443,7 @@ const TagSelector: FC<IProps> = ({
)}
</Dropdown.Menu>
</div>
{!hiddenDescription && <Form.Text>{t('hint')}</Form.Text>}
{!hiddenDescription && <Form.Text>{formText || t('hint')}</Form.Text>}
<Form.Control.Feedback type="invalid">{errMsg}</Form.Control.Feedback>
</div>
);
+161 -73
View File
@@ -19,8 +19,9 @@
import { FC, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Form, Button } from 'react-bootstrap';
import { SchemaForm, JSONSchema, initFormData, UISchema } from '@/components';
import { TagSelector } from '@/components';
import type * as Type from '@/common/interface';
import { useToast } from '@/hooks';
import {
@@ -30,80 +31,84 @@ import {
import { handleFormError, scrollToElementTop } from '@/utils';
import { writeSettingStore } from '@/stores';
const initFormData = {
reserved_tags: {
value: [] as Type.Tag[], // Replace `Type.Tag` with the correct type for `reserved_tags.value`
errorMsg: '',
isInvalid: false,
},
recommend_tags: {
value: [] as Type.Tag[],
errorMsg: '',
isInvalid: false,
},
required_tag: {
value: false,
errorMsg: '',
isInvalid: false,
},
restrict_answer: {
value: false,
errorMsg: '',
isInvalid: false,
},
};
const Index: FC = () => {
const { t } = useTranslation('translation', {
keyPrefix: 'admin.write',
});
const Toast = useToast();
const schema: JSONSchema = {
title: t('page_title'),
properties: {
restrict_answer: {
type: 'boolean',
title: t('restrict_answer.title'),
description: t('restrict_answer.text'),
default: true,
},
recommend_tags: {
type: 'string',
title: t('recommend_tags.label'),
description: t('recommend_tags.text'),
},
required_tag: {
type: 'boolean',
title: t('required_tag.title'),
description: t('required_tag.text'),
},
reserved_tags: {
type: 'string',
title: t('reserved_tags.label'),
description: t('reserved_tags.text'),
},
},
const [formData, setFormData] = useState(initFormData);
const handleValueChange = (value) => {
setFormData({
...formData,
...value,
});
};
const uiSchema: UISchema = {
restrict_answer: {
'ui:widget': 'switch',
'ui:options': {
label: t('restrict_answer.label'),
},
},
recommend_tags: {
'ui:widget': 'textarea',
'ui:options': {
rows: 10,
},
},
required_tag: {
'ui:widget': 'switch',
'ui:options': {
label: t('required_tag.label'),
},
},
reserved_tags: {
'ui:widget': 'textarea',
'ui:options': {
rows: 10,
},
},
const checkValidated = (): boolean => {
let bol = true;
const { recommend_tags, reserved_tags } = formData;
// 找出 recommend_tags 和 reserved_tags 中是否有重复的标签
// 通过标签中的 slug_name 来去重
const repeatTag = recommend_tags.value.filter((tag) =>
reserved_tags.value.some((rTag) => rTag?.slug_name === tag?.slug_name),
);
if (repeatTag.length > 0) {
handleValueChange({
recommend_tags: {
...recommend_tags,
errorMsg: t('recommend_tags.msg.contain_reserved'),
isInvalid: true,
},
});
bol = false;
const ele = document.getElementById('recommend_tags');
scrollToElementTop(ele);
} else {
handleValueChange({
recommend_tags: {
...recommend_tags,
errorMsg: '',
isInvalid: false,
},
});
}
return bol;
};
const [formData, setFormData] = useState(initFormData(schema));
const onSubmit = (evt) => {
evt.preventDefault();
evt.stopPropagation();
let recommend_tags = [];
if (formData.recommend_tags.value?.trim()) {
recommend_tags = formData.recommend_tags.value.trim().split('\n');
}
let reserved_tags = [];
if (formData.reserved_tags.value?.trim()) {
reserved_tags = formData.reserved_tags.value.trim().split('\n');
if (!checkValidated()) {
return;
}
const reqParams: Type.AdminSettingsWrite = {
recommend_tags,
reserved_tags,
recommend_tags: formData.recommend_tags.value,
reserved_tags: formData.reserved_tags.value,
required_tag: formData.required_tag.value,
restrict_answer: formData.restrict_answer.value,
};
@@ -130,12 +135,12 @@ const Index: FC = () => {
const initData = () => {
getRequireAndReservedTag().then((res) => {
if (Array.isArray(res.recommend_tags)) {
formData.recommend_tags.value = res.recommend_tags.join('\n');
formData.recommend_tags.value = res.recommend_tags;
}
formData.required_tag.value = res.required_tag;
formData.restrict_answer.value = res.restrict_answer;
if (Array.isArray(res.reserved_tags)) {
formData.reserved_tags.value = res.reserved_tags.join('\n');
formData.reserved_tags.value = res.reserved_tags;
}
setFormData({ ...formData });
});
@@ -145,20 +150,103 @@ const Index: FC = () => {
initData();
}, []);
const handleOnChange = (data) => {
setFormData(data);
};
// const handleOnChange = (data) => {
// setFormData(data);
// };
return (
<>
<h3 className="mb-4">{t('page_title')}</h3>
<SchemaForm
schema={schema}
formData={formData}
onSubmit={onSubmit}
uiSchema={uiSchema}
onChange={handleOnChange}
/>
<Form noValidate onSubmit={onSubmit}>
<Form.Group className="mb-3" controlId="reserved_tags">
<Form.Label>{t('reserved_tags.label')}</Form.Label>
<TagSelector
value={formData.reserved_tags.value}
onChange={(val) => {
handleValueChange({
reserved_tags: {
value: val,
errorMsg: '',
isInvalid: false,
},
});
}}
showRequiredTag={false}
maxTagLength={0}
tagStyleMode="simple"
formText={t('reserved_tags.text')}
isInvalid={formData.reserved_tags.isInvalid}
errMsg={formData.reserved_tags.errorMsg}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="recommend_tags">
<Form.Label>{t('recommend_tags.label')}</Form.Label>
<TagSelector
value={formData.recommend_tags.value}
onChange={(val) => {
handleValueChange({
recommend_tags: {
value: val,
errorMsg: '',
isInvalid: false,
},
});
}}
showRequiredTag={false}
tagStyleMode="simple"
formText={t('recommend_tags.text')}
isInvalid={formData.recommend_tags.isInvalid}
errMsg={formData.recommend_tags.errorMsg}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="required_tag">
<Form.Label>{t('required_tag.title')}</Form.Label>
<Form.Switch
label={t('required_tag.label')}
checked={formData.required_tag.value}
onChange={(evt) => {
handleValueChange({
required_tag: {
value: evt.target.checked,
errorMsg: '',
isInvalid: false,
},
});
}}
/>
<Form.Text>{t('required_tag.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.required_tag.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group className="mb-3" controlId="restrict_answer">
<Form.Label>{t('restrict_answer.title')}</Form.Label>
<Form.Switch
label={t('restrict_answer.label')}
checked={formData.restrict_answer.value}
onChange={(evt) => {
handleValueChange({
restrict_answer: {
value: evt.target.checked,
errorMsg: '',
isInvalid: false,
},
});
}}
/>
<Form.Text>{t('restrict_answer.text')}</Form.Text>
<Form.Control.Feedback type="invalid">
{formData.restrict_answer.errorMsg}
</Form.Control.Feedback>
</Form.Group>
<Form.Group className="mb-3">
<Button type="submit">{t('save', { keyPrefix: 'btns' })}</Button>
</Form.Group>
</Form>
</>
);
};
+1 -1
View File
@@ -30,7 +30,7 @@ const Index = create<IProps>((set) => ({
write: {
restrict_answer: true,
recommend_tags: [],
required_tag: '',
required_tag: false,
reserved_tags: [],
},
update: (params) =>