fix: optimize admin/write page content #815
This commit is contained in:
+8
-6
@@ -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:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -97,6 +97,9 @@ export const useEditor = ({
|
||||
wordWrap: 'break-word',
|
||||
wordBreak: 'break-all',
|
||||
},
|
||||
'.ͼ7, .ͼ6': {
|
||||
textDecoration: 'none',
|
||||
},
|
||||
});
|
||||
|
||||
const startState = EditorState.create({
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -30,7 +30,7 @@ const Index = create<IProps>((set) => ({
|
||||
write: {
|
||||
restrict_answer: true,
|
||||
recommend_tags: [],
|
||||
required_tag: '',
|
||||
required_tag: false,
|
||||
reserved_tags: [],
|
||||
},
|
||||
update: (params) =>
|
||||
|
||||
Reference in New Issue
Block a user