delete: 删除项目中无用的文件

master
钟良源 5 months ago
parent 6933f82ec0
commit c80b7b0143

@ -1,281 +0,0 @@
import React, { useState, useRef } from 'react';
import {
Typography,
Card,
Form,
Select,
Input,
Grid,
Space,
Button,
Message,
} from '@arco-design/web-react';
import { FormInstance } from '@arco-design/web-react/es/Form';
import axios from 'axios';
import useLocale from '@/utils/useLocale';
import locale from './locale';
import styles from './style/index.module.less';
import './mock';
function GroupForm() {
const t = useLocale(locale);
const formRef = useRef<FormInstance>();
const [loading, setLoading] = useState(false);
function submit(data) {
setLoading(true);
axios
.post('/api/groupForm', {
data,
})
.then(() => {
Message.success(t['groupForm.submitSuccess']);
})
.finally(() => {
setLoading(false);
});
}
function handleSubmit() {
formRef.current.validate().then((values) => {
submit(values);
});
}
function handleReset() {
formRef.current.resetFields();
}
return (
<div className={styles.container}>
<Form layout="vertical" ref={formRef} className={styles['form-group']}>
<Card>
<Typography.Title heading={6}>
{t['groupForm.title.video']}
</Typography.Title>
<Grid.Row gutter={80}>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.video.mode']}
field="video.mode"
initialValue={'custom'}
>
<Select placeholder={t['groupForm.placeholder.video.mode']}>
<Select.Option value="custom"></Select.Option>
<Select.Option value="mode1">1</Select.Option>
<Select.Option value="mode2">2</Select.Option>
</Select>
</Form.Item>
</Grid.Col>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.video.acquisition.resolution']}
field="video.acquisition.resolution"
>
<Select
placeholder={
t['groupForm.placeholder.video.acquisition.resolution']
}
>
<Select.Option value="resolution1">1</Select.Option>
<Select.Option value="resolution2">2</Select.Option>
<Select.Option value="resolution3">3</Select.Option>
</Select>
</Form.Item>
</Grid.Col>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.video.acquisition.frameRate']}
field="video.acquisition.frameRate"
>
<Input
placeholder={
t['groupForm.placeholder.video.acquisition.frameRate']
}
addAfter="fps"
/>
</Form.Item>
</Grid.Col>
</Grid.Row>
<Grid.Row gutter={80}>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.video.encoding.resolution']}
field="video.encoding.resolution"
>
<Select
placeholder={
t['groupForm.placeholder.video.encoding.resolution']
}
>
<Select.Option value="resolution1">1</Select.Option>
<Select.Option value="resolution2">2</Select.Option>
<Select.Option value="resolution3">3</Select.Option>
</Select>
</Form.Item>
</Grid.Col>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.video.encoding.rate.min']}
field="video.encoding.rate.min"
>
<Input
placeholder={
t['groupForm.placeholder.video.encoding.rate.min']
}
addAfter="bps"
/>
</Form.Item>
</Grid.Col>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.video.encoding.rate.max']}
field="video.encoding.rate.max"
>
<Input
placeholder={
t['groupForm.placeholder.video.encoding.rate.max']
}
addAfter="bps"
/>
</Form.Item>
</Grid.Col>
</Grid.Row>
<Grid.Row gutter={80}>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.video.encoding.rate.default']}
field="video.encoding.rate.default"
>
<Input
placeholder={
t['groupForm.placeholder.video.encoding.rate.default']
}
addAfter="bps"
/>
</Form.Item>
</Grid.Col>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.video.encoding.frameRate']}
field="video.encoding.frameRate"
>
<Input
placeholder={
t['groupForm.placeholder.video.encoding.frameRate']
}
addAfter="fps"
/>
</Form.Item>
</Grid.Col>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.video.encoding.profile']}
field="video.encoding.profile"
>
<Input
placeholder={
t['groupForm.placeholder.video.encoding.profile']
}
addAfter="bps"
/>
</Form.Item>
</Grid.Col>
</Grid.Row>
</Card>
<Card>
<Typography.Title heading={6}>
{t['groupForm.title.audio']}
</Typography.Title>
<Grid.Row gutter={80}>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.audio.mode']}
initialValue={'custom'}
field="audio.mode"
>
<Select placeholder={t['groupForm.placeholder.audio.mode']}>
<Select.Option value="custom"></Select.Option>
<Select.Option value="mode1">1</Select.Option>
<Select.Option value="mode2">2</Select.Option>
</Select>
</Form.Item>
</Grid.Col>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.audio.acquisition.channels']}
field="audio.acquisition.channels"
>
<Select
placeholder={
t['groupForm.placeholder.audio.acquisition.channels']
}
>
<Select.Option value="1">1</Select.Option>
<Select.Option value="2">2</Select.Option>
<Select.Option value="3">3</Select.Option>
</Select>
</Form.Item>
</Grid.Col>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.audio.encoding.rate']}
field="audio.encoding.rate"
>
<Input
placeholder={t['groupForm.placeholder.audio.encoding.rate']}
addAfter="bps"
/>
</Form.Item>
</Grid.Col>
</Grid.Row>
<Grid.Row gutter={80}>
<Grid.Col span={8}>
<Form.Item
label={t['groupForm.form.label.audio.encoding.profile']}
field="audio.encoding.profile"
>
<Input
placeholder={
t['groupForm.placeholder.audio.encoding.profile']
}
addAfter="fps"
/>
</Form.Item>
</Grid.Col>
</Grid.Row>
</Card>
<Card style={{ marginBottom: '40px' }}>
<Typography.Title heading={6}>
{t['groupForm.title.explanation']}
</Typography.Title>
<Form.Item
label={t['groupForm.form.label.explanation']}
field="audio.explanation"
>
<Input.TextArea
placeholder={t['groupForm.placeholder.explanation']}
/>
</Form.Item>
</Card>
</Form>
<div className={styles.actions}>
<Space>
<Button onClick={handleReset} size="large">
{t['groupForm.reset']}
</Button>
<Button
type="primary"
onClick={handleSubmit}
loading={loading}
size="large"
>
{t['groupForm.submit']}
</Button>
</Space>
</div>
</div>
);
}
export default GroupForm;

@ -1,84 +0,0 @@
const i18n = {
'en-US': {
'menu.form': 'Form',
'menu.form.group': 'Group Form',
'groupForm.title.video': 'Video Parameters',
'groupForm.title.audio': 'Audio Parameters',
'groupForm.title.explanation': 'Enter Explanation',
'groupForm.form.label.video.mode': 'Match Mode',
'groupForm.form.label.video.acquisition.resolution':
'Acquisition Resolution',
'groupForm.form.label.video.acquisition.frameRate':
'Acquisition Frame Rate',
'groupForm.form.label.video.encoding.resolution': 'Encoding Resolution',
'groupForm.form.label.video.encoding.rate.min': 'Encoding Min Rate',
'groupForm.form.label.video.encoding.rate.max': 'Encoding Max Rate',
'groupForm.form.label.video.encoding.rate.default': 'Encoding Default Rate',
'groupForm.form.label.video.encoding.frameRate': 'Encoding Frame Rate',
'groupForm.form.label.video.encoding.profile': 'Encoding Profile',
'groupForm.placeholder.video.mode': 'Please Select',
'groupForm.placeholder.video.acquisition.resolution': 'Please Select',
'groupForm.placeholder.video.acquisition.frameRate': 'Enter Range [1, 30]',
'groupForm.placeholder.video.encoding.resolution': 'Please Select',
'groupForm.placeholder.video.encoding.rate.min': 'Enter Range [150, 1800]',
'groupForm.placeholder.video.encoding.rate.max': 'Enter Range [150, 1800]',
'groupForm.placeholder.video.encoding.rate.default':
'Enter Range [150, 1800]',
'groupForm.placeholder.video.encoding.frameRate': 'Enter Range [1, 30]',
'groupForm.placeholder.video.encoding.profile': 'Enter Range [150, 1800]',
'groupForm.form.label.audio.mode': 'Match Mode',
'groupForm.form.label.audio.acquisition.channels': 'Acquisition Channels',
'groupForm.form.label.audio.encoding.rate': 'Encoding Rate',
'groupForm.form.label.audio.encoding.profile': 'Encoding Profile',
'groupForm.placeholder.audio.mode': 'Please Select',
'groupForm.placeholder.audio.acquisition.channels': 'Please Select',
'groupForm.placeholder.audio.encoding.rate': 'Enter Range [150, 1800]',
'groupForm.placeholder.audio.encoding.profile': 'Enter Range [150, 1800]',
'groupForm.form.label.explanation': 'Explanation',
'groupForm.placeholder.explanation':
'Please fill in the parameter description, no more than 200 characters',
'groupForm.submit': 'Submit',
'groupForm.reset': 'Reset',
'groupForm.submitSuccess': 'Submit Success',
},
'zh-CN': {
'menu.form': '表单页',
'menu.form.group': '分组表单',
'groupForm.title.video': '视频参数',
'groupForm.title.audio': '音频参数',
'groupForm.title.explanation': '填写说明',
'groupForm.form.label.video.mode': '匹配模式',
'groupForm.form.label.video.acquisition.resolution': '采集分辨率',
'groupForm.form.label.video.acquisition.frameRate': '采集帧率',
'groupForm.form.label.video.encoding.resolution': '编码分辨率',
'groupForm.form.label.video.encoding.rate.min': '编码码率最小值',
'groupForm.form.label.video.encoding.rate.max': '编码码率最大值',
'groupForm.form.label.video.encoding.rate.default': '编码码率默认值',
'groupForm.form.label.video.encoding.frameRate': '编码帧率',
'groupForm.form.label.video.encoding.profile': '编码profile',
'groupForm.placeholder.video.mode': '请选择',
'groupForm.placeholder.video.acquisition.resolution': '请选择',
'groupForm.placeholder.video.acquisition.frameRate': '输入范围[1, 30]',
'groupForm.placeholder.video.encoding.resolution': '请选择',
'groupForm.placeholder.video.encoding.rate.min': '输入范围[150, 1800]',
'groupForm.placeholder.video.encoding.rate.max': '输入范围[150, 1800]',
'groupForm.placeholder.video.encoding.rate.default': '输入范围[150, 1800]',
'groupForm.placeholder.video.encoding.frameRate': '输入范围[1, 30]',
'groupForm.placeholder.video.encoding.profile': '输入范围[150, 1800]',
'groupForm.form.label.audio.mode': '配置模式',
'groupForm.form.label.audio.acquisition.channels': '采集声道数',
'groupForm.form.label.audio.encoding.rate': '编码码率',
'groupForm.form.label.audio.encoding.profile': '编码profile',
'groupForm.placeholder.audio.mode': '请选择',
'groupForm.placeholder.audio.acquisition.channels': '请选择',
'groupForm.placeholder.audio.encoding.rate': '输入范围[150, 1800]',
'groupForm.placeholder.audio.encoding.profile': '输入范围[150, 1800]',
'groupForm.form.label.explanation': '参数说明',
'groupForm.placeholder.explanation': '请填写参数说明最多不超多200字',
'groupForm.submit': '提交',
'groupForm.reset': '重置',
'groupForm.submitSuccess': '提交成功',
},
};
export default i18n;

@ -1,11 +0,0 @@
import Mock from 'mockjs';
import setupMock from '@/utils/setupMock';
setupMock({
setup: () => {
// 保存表单数据
Mock.mock(new RegExp('/api/groupForm'), () => {
return true;
});
},
});

@ -1,23 +0,0 @@
.container {
overflow: hidden;
:global(.arco-card-body) {
padding: 20px 20px 10px;
}
:global(.arco-card) {
margin-bottom: 16px;
}
}
.actions {
padding: 12px 40px;
background-color: var(--color-bg-2);
display: flex;
flex-direction: row-reverse;
position: fixed;
left: 0;
right: 0;
bottom: 0;
box-shadow: 0 -3px 12px rgb(0 0 0 / 10%);
}

@ -1,257 +0,0 @@
import React, { useState } from 'react';
import {
Steps,
Form,
Input,
Select,
DatePicker,
InputTag,
Button,
Typography,
Space,
Card,
Switch,
Result,
} from '@arco-design/web-react';
import useLocale from '@/utils/useLocale';
import locale from './locale';
import styles from './style/index.module.less';
const { Title, Paragraph } = Typography;
function StepForm() {
const t = useLocale(locale);
const [current, setCurrent] = useState(1);
const [form] = Form.useForm();
const viewForm = () => {
const values = form.getFields();
form.setFields(values);
setCurrent(1);
};
const reCreateForm = () => {
form.resetFields();
setCurrent(1);
};
const toNext = async () => {
try {
await form.validate();
setCurrent(current + 1);
} catch (_) {}
};
return (
<div className={styles.container}>
<Card>
<Title heading={5}>{t['stepForm.desc.basicInfo']}</Title>
<div className={styles.wrapper}>
<Steps current={current} lineless>
<Steps.Step
title={t['stepForm.title.basicInfo']}
description={t['stepForm.desc.basicInfo']}
/>
<Steps.Step
title={t['stepForm.title.channel']}
description={t['stepForm.desc.channel']}
/>
<Steps.Step
title={t['stepForm.title.created']}
description={t['stepForm.desc.created']}
/>
</Steps>
<Form form={form} className={styles.form}>
{current === 1 && (
<Form.Item noStyle>
<Form.Item
label={t['stepForm.basicInfo.name']}
required
field="basic.name"
rules={[
{
required: true,
message: t['stepForm.basicInfo.name.required'],
},
{
validator: (value: string, callback) => {
if (!/^[\u4e00-\u9fa5a-zA-Z0-9]{1,20}$/g.test(value)) {
callback(t['stepForm.basicInfo.name.placeholder']);
}
},
},
]}
>
<Input
placeholder={t['stepForm.basicInfo.name.placeholder']}
/>
</Form.Item>
<Form.Item
label={t['stepForm.basicInfo.channelType']}
required
initialValue="app"
field="basic.channelType"
rules={[
{
required: true,
message: t['stepForm.basicInfo.channelType.required'],
},
]}
>
<Select>
<Select.Option value="app">APP</Select.Option>
<Select.Option value="site"></Select.Option>
<Select.Option value="game"></Select.Option>
</Select>
</Form.Item>
<Form.Item
label={t['stepForm.basicInfo.time']}
required
field="basic.time"
rules={[
{
required: true,
message: t['stepForm.basicInfo.time.required'],
},
]}
>
<DatePicker.RangePicker style={{ width: '100%' }} />
</Form.Item>
<Form.Item
label={t['stepForm.basicInfo.link']}
required
extra={t['stepForm.basicInfo.link.tips']}
field="basic.link"
initialValue={'https://arco.design'}
rules={[{ required: true }]}
>
<Input
placeholder={t['stepForm.basicInfo.link.placeholder']}
/>
</Form.Item>
</Form.Item>
)}
{current === 2 && (
<Form.Item noStyle>
<Form.Item
label={t['stepForm.channel.source']}
required
field="channel.source"
rules={[
{
required: true,
message: t['stepForm.channel.source.required'],
},
]}
>
<Input
placeholder={t['stepForm.channel.source.placeholder']}
/>
</Form.Item>
<Form.Item
label={t['stepForm.channel.media']}
required
field="channel.media"
rules={[
{
required: true,
message: t['stepForm.channel.media.required'],
},
]}
>
<Input
placeholder={t['stepForm.channel.media.placeholder']}
/>
</Form.Item>
<Form.Item
label={t['stepForm.channel.keywords']}
required
field="channel.keywords"
initialValue={['今日头条', '火山']}
rules={[{ required: true }]}
>
<InputTag />
</Form.Item>
<Form.Item
label={t['stepForm.channel.remind']}
required
initialValue={true}
field="channel.remind"
triggerPropName="checked"
rules={[{ required: true }]}
>
<Switch />
</Form.Item>
<Form.Item
label={t['stepForm.channel.content']}
required
field="channel.content"
rules={[
{
required: true,
message: t['stepForm.channel.content.required'],
},
]}
>
<Input.TextArea
placeholder={t['stepForm.channel.content.placeholder']}
/>
</Form.Item>
</Form.Item>
)}
{current !== 3 ? (
<Form.Item label=" ">
<Space>
{current === 2 && (
<Button
size="large"
onClick={() => setCurrent(current - 1)}
>
{t['stepForm.prev']}
</Button>
)}
{current !== 3 && (
<Button type="primary" size="large" onClick={toNext}>
{t['stepForm.next']}
</Button>
)}
</Space>
</Form.Item>
) : (
<Form.Item noStyle>
<Result
status="success"
title={t['stepForm.created.success.title']}
subTitle={t['stepForm.created.success.desc']}
extra={[
<Button
key="reset"
style={{ marginRight: 16 }}
onClick={viewForm}
>
{t['stepForm.created.success.view']}
</Button>,
<Button key="again" type="primary" onClick={reCreateForm}>
{t['stepForm.created.success.again']}
</Button>,
]}
/>
</Form.Item>
)}
</Form>
</div>
{current === 3 && (
<div className={styles['form-extra']}>
<Title heading={6}>{t['stepForm.created.extra.title']}</Title>
<Paragraph type="secondary">
{t['stepForm.created.extra.desc']}
<Button type="text">{t['stepForm.created.extra.detail']}</Button>
</Paragraph>
</div>
)}
</Card>
</div>
);
}
export default StepForm;

@ -1,94 +0,0 @@
const i18n = {
'en-US': {
'menu.form': 'Form',
'menu.form.step': 'Step Form',
'stepForm.title': 'Create a channel form',
'stepForm.next': 'Next',
'stepForm.prev': 'Prev',
'stepForm.title.basicInfo': 'Basic Information',
'stepForm.desc.basicInfo': 'Create event channel',
'stepForm.title.channel': 'Channel Information',
'stepForm.desc.channel': 'Enter detailed channel content',
'stepForm.title.created': 'Complete creation',
'stepForm.desc.created': 'Created successfully',
'stepForm.basicInfo.name': 'Event name',
'stepForm.basicInfo.name.required': 'Please enter the event name',
'stepForm.basicInfo.name.placeholder':
'Enter Chinese characters, letters or numbers, up to 20 characters',
'stepForm.basicInfo.channelType': 'Channel Type',
'stepForm.basicInfo.channelType.required': 'Please select the channel type',
'stepForm.basicInfo.time': 'Promotion time',
'stepForm.basicInfo.time.required': 'Please select the promotion time',
'stepForm.basicInfo.link': 'Promotion URL',
'stepForm.basicInfo.link.placeholder':
'Please enter the promotion page address',
'stepForm.basicInfo.link.tips':
'Such as Android or iOS download address, intermediate redirect URL, the URL must start with http:// or https://',
'stepForm.channel.source': 'Advertising source',
'stepForm.channel.source.required': 'Please enter the advertising source',
'stepForm.channel.source.placeholder': 'Referral address: sohu, sina',
'stepForm.channel.media': 'Advertising medium',
'stepForm.channel.media.required': 'Please enter the advertising medium',
'stepForm.channel.media.placeholder': 'Marketing media: cpc, bannner, edm',
'stepForm.channel.keywords': 'Key words',
'stepForm.channel.remind': 'Push reminder',
'stepForm.channel.content': 'Advertising content',
'stepForm.channel.content.required': 'Please enter the advertising content',
'stepForm.channel.content.placeholder':
'Please enter the description of the advertisement content, no more than 200 words',
'stepForm.created.success.title': 'Created successfully',
'stepForm.created.success.desc': 'Form created successfully',
'stepForm.created.success.view': 'View form',
'stepForm.created.success.again': 'Create again',
'stepForm.created.extra.title': 'Channel form description',
'stepForm.created.extra.desc':
'Advertiser channel promotion supports the tracking of users who place ads on third-party advertisers to download App users, such as launching App download advertisements on Toutiao channels, and tracking users who activate App by downloading on channels. ',
'stepForm.created.extra.detail': 'Details',
},
'zh-CN': {
'menu.form': '表单页',
'menu.form.step': '分布表单',
'stepForm.title': '创建渠道表单',
'stepForm.next': '下一步',
'stepForm.prev': '上一步',
'stepForm.title.basicInfo': '基本信息',
'stepForm.desc.basicInfo': '创建活动渠道',
'stepForm.title.channel': '输入渠道信息',
'stepForm.desc.channel': '输入详细的渠道内容',
'stepForm.title.created': '完成创建',
'stepForm.desc.created': '创建成功',
'stepForm.basicInfo.name': '活动名称',
'stepForm.basicInfo.name.required': '请输入活动名称',
'stepForm.basicInfo.name.placeholder': '输入汉字、字母或数字最多20字符',
'stepForm.basicInfo.channelType': '渠道类型',
'stepForm.basicInfo.channelType.required': '请选择渠道类型',
'stepForm.basicInfo.time': '推广时间',
'stepForm.basicInfo.time.required': '请选择推广时间',
'stepForm.basicInfo.link': '推广地址',
'stepForm.basicInfo.link.placeholder': '请输入推广页面地址',
'stepForm.basicInfo.link.tips':
'如 Android 或 iOS 的下载地址、中间跳转URL网址必须以 http:// 或 https:// 开头',
'stepForm.channel.source': '广告来源',
'stepForm.channel.source.required': '请输入广告来源',
'stepForm.channel.source.placeholder': '引荐来源地址sohu、sina',
'stepForm.channel.media': '广告媒介',
'stepForm.channel.media.required': '请输入广告媒介',
'stepForm.channel.media.placeholder': '营销媒介cpc、bannner、edm',
'stepForm.channel.keywords': '关键词',
'stepForm.channel.remind': '推送提醒',
'stepForm.channel.content': '广告内容',
'stepForm.channel.content.required': '请输入广告内容',
'stepForm.channel.content.placeholder':
'请输入广告内容介绍最多不超过200字',
'stepForm.created.success.title': '创建成功',
'stepForm.created.success.desc': '表单创建成功',
'stepForm.created.success.view': '查看表单',
'stepForm.created.success.again': '再次创建',
'stepForm.created.extra.title': '渠道表单说明',
'stepForm.created.extra.desc':
'广告商渠道推广支持追踪在第三方广告商投放广告下载App用户的场景例如在今日头条渠道投放下载App广告追踪通过在渠道下载激活App的用户。',
'stepForm.created.extra.detail': '查看详情',
},
};
export default i18n;

@ -1,11 +0,0 @@
import Mock from 'mockjs';
import setupMock from '@/utils/setupMock';
setupMock({
setup: () => {
// 保存表单数据
Mock.mock(new RegExp('/api/groupForm'), () => {
return true;
});
},
});

@ -1,39 +0,0 @@
.container {
:global(.arco-card-body) {
> h5 {
margin: 0;
}
padding: 20px;
}
}
.wrapper {
width: 624px;
margin: 0 auto;
padding-top: 56px;
padding-bottom: 70px;
}
.form {
width: 100%;
box-sizing: border-box;
margin-top: 76px;
padding-right: 76px;
}
.form-extra {
width: 895px;
margin: 54px auto;
background-color: var(--color-fill-1);
padding: 20px;
margin-bottom: 120px;
> h6 {
margin-top: 0;
}
> div {
margin-bottom: 0;
}
}

@ -1,28 +0,0 @@
import React from 'react';
import { Card } from '@arco-design/web-react';
import cs from 'classnames';
import { IconPlus } from '@arco-design/web-react/icon';
import styles from './style/index.module.less';
interface AddCardProps {
description?: string;
}
function AddCard(props: AddCardProps) {
return (
<Card
className={cs(styles['card-block'], styles['add-card'])}
title={null}
bordered={true}
size="small"
>
<div className={styles.content}>
<div className={styles['add-icon']}>
<IconPlus />
</div>
<div className={styles.description}>{props.description}</div>
</div>
</Card>
);
}
export default AddCard;

@ -1,255 +0,0 @@
import React, { useEffect, useState } from 'react';
import cs from 'classnames';
import {
Button,
Switch,
Tag,
Card,
Descriptions,
Typography,
Dropdown,
Menu,
Skeleton,
} from '@arco-design/web-react';
import {
IconStarFill,
IconThumbUpFill,
IconSunFill,
IconFaceSmileFill,
IconPenFill,
IconCheckCircleFill,
IconCloseCircleFill,
IconMore,
} from '@arco-design/web-react/icon';
import PermissionWrapper from '@/components/PermissionWrapper';
import useLocale from '@/utils/useLocale';
import locale from './locale';
import { QualityInspection, BasicCard } from './interface';
import styles from './style/index.module.less';
interface CardBlockType {
type: 'quality' | 'service' | 'rules';
card: QualityInspection & BasicCard;
loading?: boolean;
}
const IconList = [
IconStarFill,
IconThumbUpFill,
IconSunFill,
IconFaceSmileFill,
IconPenFill,
].map((Tag, index) => <Tag key={index} />);
const { Paragraph } = Typography;
function CardBlock(props: CardBlockType) {
const { type, card = {} } = props;
const [visible, setVisible] = useState(false);
const [status, setStatus] = useState(card.status);
const [loading, setLoading] = useState(props.loading);
const t = useLocale(locale);
const changeStatus = async () => {
setLoading(true);
await new Promise((resolve) =>
setTimeout(() => {
setStatus(status !== 1 ? 1 : 0);
resolve(null);
}, 1000)
).finally(() => setLoading(false));
};
useEffect(() => {
setLoading(props.loading);
}, [props.loading]);
useEffect(() => {
if (card.status !== status) {
setStatus(card.status);
}
}, [card.status]);
const getTitleIcon = () => {
if (type === 'service' && typeof card.icon === 'number') {
return (
<div className={styles.icon}>
{IconList[card.icon % IconList.length]}
</div>
);
}
return null;
};
const getButtonGroup = () => {
if (type === 'quality') {
return (
<>
<PermissionWrapper
requiredPermissions={[
{ resource: /^menu.list.*/, actions: ['read'] },
]}
>
<Button
type="primary"
style={{ marginLeft: '12px' }}
loading={loading}
>
{t['cardList.options.qualityInspection']}
</Button>
</PermissionWrapper>
<PermissionWrapper
requiredPermissions={[
{ resource: /^menu.list.*/, actions: ['write'] },
]}
>
<Button loading={loading}>{t['cardList.options.remove']}</Button>
</PermissionWrapper>
</>
);
}
if (type === 'service') {
return (
<>
{status === 1 ? (
<Button loading={loading} onClick={changeStatus}>
{t['cardList.options.cancel']}
</Button>
) : (
<Button type="outline" loading={loading} onClick={changeStatus}>
{status === 0
? t['cardList.options.subscribe']
: t['cardList.options.renewal']}
</Button>
)}
</>
);
}
return (
<Switch checked={!!status} loading={loading} onChange={changeStatus} />
);
};
const getStatus = () => {
if (type === 'rules' && status) {
return (
<Tag
color="green"
icon={<IconCheckCircleFill />}
className={styles.status}
size="small"
>
{t['cardList.tag.activated']}
</Tag>
);
}
switch (status) {
case 1:
return (
<Tag
color="green"
icon={<IconCheckCircleFill />}
className={styles.status}
size="small"
>
{t['cardList.tag.opened']}
</Tag>
);
case 2:
return (
<Tag
color="red"
icon={<IconCloseCircleFill />}
className={styles.status}
size="small"
>
{t['cardList.tag.expired']}
</Tag>
);
default:
return null;
}
};
const getContent = () => {
if (loading) {
return (
<Skeleton
text={{ rows: type !== 'quality' ? 3 : 2 }}
animation
className={styles['card-block-skeleton']}
/>
);
}
if (type !== 'quality') {
return <Paragraph>{card.description}</Paragraph>;
}
return (
<Descriptions
column={2}
data={[
{ label: '待质检数', value: card.qualityCount },
{ label: '积压时长', value: `${card.duration}s` },
{ label: '待抽检数', value: card.randomCount },
]}
/>
);
};
const className = cs(styles['card-block'], styles[`${type}-card`]);
return (
<Card
bordered={true}
className={className}
size="small"
title={
loading ? (
<Skeleton
animation
text={{ rows: 1, width: ['100%'] }}
style={{ width: '120px', height: '24px' }}
className={styles['card-block-skeleton']}
/>
) : (
<>
<div
className={cs(styles.title, {
[styles['title-more']]: visible,
})}
>
{getTitleIcon()}
{card.title}
{getStatus()}
<Dropdown
droplist={
<Menu>
{['操作1', '操作2'].map((item, key) => (
<Menu.Item key={key.toString()}>{item}</Menu.Item>
))}
</Menu>
}
trigger="click"
onVisibleChange={setVisible}
popupVisible={visible}
>
<div className={styles.more}>
<IconMore />
</div>
</Dropdown>
</div>
<div className={styles.time}>{card.time}</div>
</>
)
}
>
<div className={styles.content}>{getContent()}</div>
<div className={styles.extra}>{getButtonGroup()}</div>
</Card>
);
}
export default CardBlock;

@ -1,95 +0,0 @@
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { Tabs, Card, Input, Typography, Grid } from '@arco-design/web-react';
import useLocale from '@/utils/useLocale';
import locale from './locale';
import styles from './style/index.module.less';
import CardBlock from './card-block';
import AddCard from './card-add';
import { QualityInspection, BasicCard } from './interface';
import './mock';
const { Title } = Typography;
const { Row, Col } = Grid;
const defaultList = new Array(10).fill({});
export default function ListCard() {
const t = useLocale(locale);
const [loading, setLoading] = useState(true);
const [data, setData] = useState({
quality: defaultList,
service: defaultList,
rules: defaultList,
});
const [activeKey, setActiveKey] = useState('all');
const getData = () => {
axios
.get('/api/cardList')
.then((res) => {
setData(res.data);
})
.finally(() => setLoading(false));
};
useEffect(() => {
getData();
}, []);
7;
const getCardList = (
list: Array<BasicCard & QualityInspection>,
type: keyof typeof data
) => {
return (
<Row gutter={24} className={styles['card-content']}>
{type === 'quality' && (
<Col xs={24} sm={12} md={8} lg={6} xl={6} xxl={6}>
<AddCard description={t['cardList.add.quality']} />
</Col>
)}
{list.map((item, index) => (
<Col xs={24} sm={12} md={8} lg={6} xl={6} xxl={6} key={index}>
<CardBlock card={item} type={type} loading={loading} />
</Col>
))}
</Row>
);
};
return (
<Card>
<Title heading={6}>{t['menu.list.card']}</Title>
<Tabs
activeTab={activeKey}
type="rounded"
onChange={setActiveKey}
extra={
<Input.Search
style={{ width: '240px' }}
placeholder={t[`cardList.tab.${activeKey}.placeholder`]}
/>
}
>
<Tabs.TabPane key="all" title={t['cardList.tab.title.all']} />
<Tabs.TabPane key="quality" title={t['cardList.tab.title.quality']} />
<Tabs.TabPane key="service" title={t['cardList.tab.title.service']} />
<Tabs.TabPane key="rules" title={t['cardList.tab.title.rules']} />
</Tabs>
<div className={styles.container}>
{activeKey === 'all' ? (
Object.entries(data).map(([key, list]) => (
<div key={key}>
<Title heading={6}>{t[`cardList.tab.title.${key}`]}</Title>
{getCardList(list, key as keyof typeof data)}
</div>
))
) : (
<div className={styles['single-content']}>
{getCardList(data[activeKey], activeKey as keyof typeof data)}
</div>
)}
</div>
</Card>
);
}

@ -1,13 +0,0 @@
export interface QualityInspection {
title?: string;
time?: string;
qualityCount?: number;
randomCount?: number;
duration?: number;
}
export interface BasicCard {
icon?: number;
status?: 0 | 1 | 2;
description?: string;
}

@ -1,66 +0,0 @@
const i18n = {
'en-US': {
'menu.list': 'List',
'menu.list.card': 'Card List',
'cardList.tab.title.all': 'All',
'cardList.tab.title.quality': 'Content quality',
'cardList.tab.title.service': 'Service opening',
'cardList.tab.title.rules': 'Rule presets',
'cardList.tab.all.placeholder': 'Search',
'cardList.tab.quality.placeholder': 'Search queue',
'cardList.tab.service.placeholder': 'Search service',
'cardList.tab.rules.placeholder': 'Search rule',
'cardList.searchInput.placeholder': 'Search service',
'cardList.add.quality': 'Create quality inspection queue',
'cardList.enable': 'Enable',
'cardList.disable': 'Disable',
'cardList.action': 'action',
'cardList.detail': 'Detail',
'cardList.tab.title.announcement': 'Recent Announcement',
'cardList.announcement.noData': 'No announcement',
'cardList.statistic.enable': 'Enable',
'cardList.statistic.disable': 'Disable',
'cardList.statistic.applicationNum': 'Applications',
'cardList.options.qualityInspection': 'Quality inspection',
'cardList.options.remove': 'Remove',
'cardList.options.cancel': 'Cancel',
'cardList.options.subscribe': 'Subscribe',
'cardList.options.renewal': 'Renewal',
'cardList.tag.activated': 'Activated',
'cardList.tag.opened': 'Already Opened',
'cardList.tag.expired': 'Expired',
},
'zh-CN': {
'menu.list': '列表页',
'menu.list.card': '卡片列表',
'cardList.tab.title.all': '全部',
'cardList.tab.title.quality': '内容质检',
'cardList.tab.title.service': '服务开通',
'cardList.tab.title.rules': '规则预置',
'cardList.tab.all.placeholder': '搜索',
'cardList.tab.quality.placeholder': '搜索队列',
'cardList.tab.service.placeholder': '搜索服务',
'cardList.tab.rules.placeholder': '搜索规则',
'cardList.searchInput.placeholder': '搜索服务',
'cardList.add.quality': '点击创建质检内容队列',
'cardList.enable': '启用',
'cardList.disable': '禁用',
'cardList.action': '操作',
'cardList.detail': '详细信息',
'cardList.tab.title.announcement': '最近公告',
'cardList.announcement.noData': '暂无公告',
'cardList.statistic.enable': '已启用',
'cardList.statistic.disable': '未启用',
'cardList.statistic.applicationNum': '应用数',
'cardList.options.qualityInspection': '质检',
'cardList.options.remove': '删除',
'cardList.options.cancel': '取消开通',
'cardList.options.subscribe': '开通服务',
'cardList.options.renewal': '续约服务',
'cardList.tag.activated': '已启用',
'cardList.tag.opened': '已开通',
'cardList.tag.expired': '已过期',
},
};
export default i18n;

@ -1,106 +0,0 @@
import Mock from 'mockjs';
import dayjs from 'dayjs';
import setupMock from '@/utils/setupMock';
const qualityCategory = ['视频类', '图文类', '纯文本'];
const qualityName = ['历史导入', '内容版权', '敏感内容', '商业品牌'];
const serviceName = [
'漏斗分析',
'用户分布',
'资源分发',
'用户画像分析',
'事件分析',
];
const serviceDescriptions = [
'用户行为分析之漏斗分析模型是企业实现精细化运营、进行用户行为分析的重要数据分析模型。 ',
'快速诊断用户人群,地域细分情况,了解数据分布的集中度,以及主要的数据分布的区间段是什么。',
'移动端动态化资源分发解决方案。提供稳定大流量服务支持、灵活定制的分发圈选规则,通过离线化预加载。 ',
'用户画像就是将典型用户信息标签化,根据用户特征、业务场景和用户行为等信息,构建一个标签化的用户模型。 ',
'事件分析即可进行筛选、分组、聚合的灵活多维数据分析。详情请点击卡片。',
];
const rulesName = [
'内容屏蔽规则',
'内容置顶规则',
'内容加权规则',
'内容分发规则',
'多语言文字符号识别',
];
const rulesDescription = [
'用户在执行特定的内容分发任务时,可使用内容屏蔽规则根据特定标签,过滤内容集合。 ',
'该规则支持用户在执行特定内容分发任务时,对固定的几条内容置顶。',
'选定内容加权规则后可自定义从不同内容集合获取内容的概率。',
'内容分发时对某些内容需要固定在C端展示的位置。',
'精准识别英语、维语、藏语、蒙古语、朝鲜语等多种语言以及emoji表情形态的语义识别。',
];
const getQualityCard = () => {
const { list } = Mock.mock({
'list|10': [
{
title: () =>
`${Mock.Random.pick(qualityCategory)}-${Mock.Random.pick(
qualityName
)}`,
time: () =>
dayjs()
.subtract(Mock.Random.natural(0, 30), 'days')
.format('YYYY-MM-DD HH:mm:ss'),
qualityCount: () => Mock.Random.natural(100, 500),
randomCount: () => Mock.Random.natural(0, 100),
duration: () => Mock.Random.natural(0, 200),
},
],
});
return list;
};
const getServiceCard = () => {
const { list } = Mock.mock({
'list|10': [
{
icon: () => Mock.Random.natural(0, serviceName.length - 1),
title: function () {
return serviceName[this.icon];
},
description: function () {
return serviceDescriptions[this.icon];
},
status: () => Mock.Random.natural(0, 2),
},
],
});
return list;
};
const getRulesCard = () => {
const { list } = Mock.mock({
'list|10': [
{
index: () => Mock.Random.natural(0, rulesName.length - 1),
title: function () {
return rulesName[this.index];
},
description: function () {
return rulesDescription[this.index];
},
status: () => Mock.Random.natural(0, 1),
},
],
});
return list;
};
setupMock({
setup: () => {
Mock.mock(new RegExp('/api/cardList'), () => {
return {
quality: getQualityCard(),
service: getServiceCard(),
rules: getRulesCard(),
};
});
},
});

@ -1,156 +0,0 @@
.container {
:global(.arco-list-content) {
overflow-x: hidden;
}
:global(.arco-card-meta-title) {
font-size: 14px;
}
h6 {
font-size: 14px;
margin-top: 16px;
margin-bottom: 12px;
}
.card-content {
min-height: 180px;
width: 100%;
}
.single-content {
margin-top: 30px;
}
}
.card-block {
margin-bottom: 16px;
:global(.arco-card-header) {
border-bottom: none;
height: auto;
padding: 16px;
padding-bottom: 0;
}
.title {
display: flex;
line-height: 24px;
align-items: center;
font-size: 14px;
font-weight: 500;
.icon {
height: 24px;
width: 24px;
color: var(--color-white);
background: #626aea;
text-align: center;
line-height: 24px;
border-radius: 50%;
margin-right: 8px;
}
.status {
margin-left: 12px;
}
.more {
color: var(--color-text-4);
font-size: 16px;
position: absolute;
right: 16px;
cursor: pointer;
opacity: 0;
}
}
.title-more {
.more {
opacity: 1;
}
}
.time,
.content > :global(.arco-typography),
:global(.arco-descriptions-item-label),
:global(.arco-descriptions-item-value) {
font-size: 12px;
font-weight: 400;
color: var(--color-text-3);
padding: 0;
line-height: 20px;
}
:global(.arco-descriptions-item-value) {
color: var(--color-text-2);
padding-left: 6px;
}
.content {
height: 48px;
}
.extra {
display: flex;
flex-direction: row-reverse;
}
&-skeleton {
:global(.arco-skeleton-content .arco-skeleton-text-row:not(:last-child)) {
height: 14px;
margin-bottom: 8px;
}
}
}
.card-block:hover {
box-shadow: 4px 4px 10px rgba(0, 0, 0, 10%);
.title {
.more {
opacity: 1;
}
}
}
.add-card {
text-align: center;
cursor: pointer;
.add-icon {
font-size: 22px;
}
.description {
margin-top: 16px;
color: var(--color-text-3);
font-weight: 400;
}
:global(.arco-card-body) {
padding-top: 52px;
padding-bottom: 64px;
}
}
.service-card {
:global(.arco-card-body) {
padding: 12px 16px 16px 48px;
}
.content {
margin-bottom: 10px;
height: 60px;
}
}
.rules-card {
:global(.arco-card-body) {
padding: 12px 16px 16px;
}
.content {
margin-bottom: 14px;
}
}

@ -1,21 +0,0 @@
import axios from 'axios';
import { useEffect, useState } from 'react';
export default <T>(url: string, defaultValue: T[]): [boolean, T[]] => {
const [loading, setLoading] = useState(false);
const [data, setData] = useState<T[]>(defaultValue);
useEffect(() => {
setLoading(true);
axios
.get(url)
.then((res) => {
setData(res.data);
})
.finally(() => {
setLoading(false);
});
}, [url]);
return [loading, data];
};

@ -1,91 +0,0 @@
import React from 'react';
import { Button, Typography, Badge } from '@arco-design/web-react';
import IconText from './icons/text.svg';
import IconHorizontalVideo from './icons/horizontal.svg';
import IconVerticalVideo from './icons/vertical.svg';
import dayjs from 'dayjs';
import styles from './style/index.module.less';
const { Text } = Typography;
export const ContentType = ['图文', '横版短视频', '竖版短视频'];
export const FilterType = ['规则筛选', '人工'];
export const Status = ['未上线', '已上线'];
const ContentIcon = [
<IconText key={0} />,
<IconHorizontalVideo key={1} />,
<IconVerticalVideo key={2} />,
];
export function getColumns(
t: any,
callback: (record: Record<string, any>, type: string) => Promise<void>
) {
return [
{
title: t['searchTable.columns.id'],
dataIndex: 'id',
render: (value) => <Text copyable>{value}</Text>,
},
{
title: t['searchTable.columns.name'],
dataIndex: 'name',
},
{
title: t['searchTable.columns.contentType'],
dataIndex: 'contentType',
render: (value) => (
<div className={styles['content-type']}>
{ContentIcon[value]}
{ContentType[value]}
</div>
),
},
{
title: t['searchTable.columns.filterType'],
dataIndex: 'filterType',
render: (value) => FilterType[value],
},
{
title: t['searchTable.columns.contentNum'],
dataIndex: 'count',
sorter: (a, b) => a.count - b.count,
render(x) {
return Number(x).toLocaleString();
},
},
{
title: t['searchTable.columns.createdTime'],
dataIndex: 'createdTime',
render: (x) => dayjs().subtract(x, 'days').format('YYYY-MM-DD HH:mm:ss'),
sorter: (a, b) => b.createdTime - a.createdTime,
},
{
title: t['searchTable.columns.status'],
dataIndex: 'status',
render: (x) => {
if (x === 0) {
return <Badge status="error" text={Status[x]}></Badge>;
}
return <Badge status="success" text={Status[x]}></Badge>;
},
},
{
title: t['searchTable.columns.operations'],
dataIndex: 'operations',
headerCellStyle: { paddingLeft: '15px' },
render: (_, record) => (
<Button
type="text"
size="small"
onClick={() => callback(record, 'view')}
>
{t['searchTable.columns.operations.view']}
</Button>
),
},
];
}
export default () => ContentIcon;

@ -1,135 +0,0 @@
import React, { useContext } from 'react';
import dayjs from 'dayjs';
import {
Form,
Input,
Select,
DatePicker,
Button,
Grid,
} from '@arco-design/web-react';
import { GlobalContext } from '@/context';
import locale from './locale';
import useLocale from '@/utils/useLocale';
import { IconRefresh, IconSearch } from '@arco-design/web-react/icon';
import { ContentType, FilterType, Status } from './constants';
import styles from './style/index.module.less';
const { Row, Col } = Grid;
const { useForm } = Form;
function SearchForm(props: {
onSearch: (values: Record<string, any>) => void;
}) {
const { lang } = useContext(GlobalContext);
const t = useLocale(locale);
const [form] = useForm();
const handleSubmit = () => {
const values = form.getFieldsValue();
props.onSearch(values);
};
const handleReset = () => {
form.resetFields();
props.onSearch({});
};
const colSpan = lang === 'zh-CN' ? 8 : 12;
return (
<div className={styles['search-form-wrapper']}>
<Form
form={form}
className={styles['search-form']}
labelAlign="left"
labelCol={{ span: 5 }}
wrapperCol={{ span: 19 }}
>
<Row gutter={24}>
<Col span={colSpan}>
<Form.Item label={t['searchTable.columns.id']} field="id">
<Input placeholder={t['searchForm.id.placeholder']} allowClear />
</Form.Item>
</Col>
<Col span={colSpan}>
<Form.Item label={t['searchTable.columns.name']} field="name">
<Input
allowClear
placeholder={t['searchForm.name.placeholder']}
/>
</Form.Item>
</Col>
<Col span={colSpan}>
<Form.Item
label={t['searchTable.columns.contentType']}
field="contentType"
>
<Select
placeholder={t['searchForm.all.placeholder']}
options={ContentType.map((item, index) => ({
label: item,
value: index,
}))}
mode="multiple"
allowClear
/>
</Form.Item>
</Col>
<Col span={colSpan}>
<Form.Item
label={t['searchTable.columns.filterType']}
field="filterType"
>
<Select
placeholder={t['searchForm.all.placeholder']}
options={FilterType.map((item, index) => ({
label: item,
value: index,
}))}
mode="multiple"
allowClear
/>
</Form.Item>
</Col>
<Col span={colSpan}>
<Form.Item
label={t['searchTable.columns.createdTime']}
field="createdTime"
>
<DatePicker.RangePicker
allowClear
style={{ width: '100%' }}
disabledDate={(date) => dayjs(date).isAfter(dayjs())}
/>
</Form.Item>
</Col>
<Col span={colSpan}>
<Form.Item label={t['searchTable.columns.status']} field="status">
<Select
placeholder={t['searchForm.all.placeholder']}
options={Status.map((item, index) => ({
label: item,
value: index,
}))}
mode="multiple"
allowClear
/>
</Form.Item>
</Col>
</Row>
</Form>
<div className={styles['right-button']}>
<Button type="primary" icon={<IconSearch />} onClick={handleSubmit}>
{t['searchTable.form.search']}
</Button>
<Button icon={<IconRefresh />} onClick={handleReset}>
{t['searchTable.form.reset']}
</Button>
</div>
</div>
);
}
export default SearchForm;

@ -1,20 +0,0 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect y="1" width="14" height="14" rx="1.67" fill="#FFDDE0"/>
<path d="M0.0708579 2.61134C0.0786468 1.68906 0.832619 0.94772 1.7549 0.955509L12.414 1.04553C13.3363 1.05332 14.0776 1.80729 14.0699 2.72957L13.999 11.1181L1.49778e-05 10.9999L0.0708579 2.61134Z" fill="#FF8B96"/>
<g opacity="0.9" filter="url(#filter0_d_422_41703)">
<path d="M5.32269 7.78472V4.65415C5.32269 4.18777 5.83148 3.8997 6.23139 4.13965L8.8402 5.70494C9.2286 5.93798 9.2286 6.50089 8.8402 6.73393L6.23139 8.29922C5.83148 8.53917 5.32269 8.2511 5.32269 7.78472Z" fill="#FFEDEF"/>
</g>
<rect opacity="0.6" width="10" height="1" rx="0.4" transform="matrix(1 0 0 -1 2.04199 13.5156)" fill="#FF727F"/>
<defs>
<filter id="filter0_d_422_41703" x="3.6636" y="2.39413" width="7.12699" height="7.65071" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="0.829547"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.8625 0 0 0 0 0.280312 0 0 0 0 0.33552 0 0 0 0.8 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_422_41703"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_422_41703" result="shape"/>
</filter>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

@ -1,41 +0,0 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 2C0 0.89543 0.895431 0 2 0H12C13.1046 0 14 0.895431 14 2V12C14 13.1046 13.1046 14 12 14H2C0.895431 14 0 13.1046 0 12V2Z" fill="url(#paint0_linear_422_41656)"/>
<g opacity="0.9" filter="url(#filter0_d_422_41656)">
<path d="M4.48218 3.23096C4.81406 3.23101 5.13232 3.36289 5.36695 3.59758C5.60159 3.83228 5.73337 4.15056 5.73332 4.48241C5.73326 4.81426 5.60137 5.13249 5.36666 5.36711C5.13195 5.60172 4.81364 5.73349 4.48176 5.73344C4.14989 5.73333 3.83165 5.6014 3.59705 5.36666C3.36246 5.13193 3.23072 4.81363 3.23084 4.48178C3.23095 4.14993 3.36289 3.83172 3.59764 3.59714C3.83239 3.36257 4.15072 3.23085 4.4826 3.23096H4.48218Z" fill="white"/>
</g>
<g clip-path="url(#clip0_422_41656)">
<g opacity="0.9" filter="url(#filter1_d_422_41656)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.92035 17.5178C10.868 17.5178 12.447 15.0428 12.447 11.9896C12.447 8.93649 10.868 6.46143 8.92035 6.46143C7.69985 6.46143 6.62416 7.43332 5.99105 8.91033C5.58344 8.38402 5.03884 8.06253 4.44061 8.06253C3.17724 8.06253 2.15308 9.49636 2.15308 11.2651C2.15308 13.0338 3.17724 14.4676 4.44061 14.4676C4.87779 14.4676 5.28633 14.2959 5.6337 13.9981C6.14641 16.0582 7.42464 17.5178 8.92035 17.5178Z" fill="white"/>
</g>
</g>
<defs>
<filter id="filter0_d_422_41656" x="0.308552" y="2.25686" width="8.34704" height="8.34701" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1.94819"/>
<feGaussianBlur stdDeviation="1.46114"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.207843 0 0 0 0 0.701961 0 0 0 0 0.94902 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_422_41656"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_422_41656" result="shape"/>
</filter>
<filter id="filter1_d_422_41656" x="-0.5182" y="5.571" width="15.6364" height="16.3989" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1.78085"/>
<feGaussianBlur stdDeviation="1.33564"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.207843 0 0 0 0 0.701961 0 0 0 0 0.94902 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_422_41656"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_422_41656" result="shape"/>
</filter>
<linearGradient id="paint0_linear_422_41656" x1="0" y1="0" x2="9.36513" y2="14.6703" gradientUnits="userSpaceOnUse">
<stop stop-color="#1B9FFF"/>
<stop offset="0.0001" stop-color="#479AFB"/>
<stop offset="1" stop-color="#77C6FF"/>
</linearGradient>
<clipPath id="clip0_422_41656">
<rect x="2.15375" y="6.46143" width="10.2939" height="4.95632" rx="2" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

@ -1,24 +0,0 @@
<svg width="13" height="16" viewBox="0 0 13 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect opacity="0.9" width="13" height="16" rx="1.67" fill="url(#paint0_linear_422_41748)"/>
<g opacity="0.9" filter="url(#filter0_d_422_41748)">
<path d="M5 7.91745V5.08255C5 4.61129 5.51837 4.32398 5.918 4.57375L8.18592 5.9912C8.56192 6.2262 8.56192 6.7738 8.18592 7.0088L5.918 8.42625C5.51837 8.67602 5 8.38871 5 7.91745Z" fill="white"/>
</g>
<rect opacity="0.8" width="9" height="1" rx="0.315789" transform="matrix(1 0 0 -1 2 12)" fill="#FFF5E8"/>
<rect opacity="0.8" width="6" height="1" rx="0.315789" transform="matrix(1 0 0 -1 2 14)" fill="#FFF5E8"/>
<defs>
<filter id="filter0_d_422_41748" x="3.73684" y="3.21853" width="5.99424" height="6.56294" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="0.631579"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.870833 0 0 0 0 0.554311 0 0 0 0 0.148767 0 0 0 0.8 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_422_41748"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_422_41748" result="shape"/>
</filter>
<linearGradient id="paint0_linear_422_41748" x1="0.5" y1="0.5" x2="12.5" y2="15.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF8A00"/>
<stop offset="1" stop-color="#FFC581"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

@ -1,120 +0,0 @@
import React, { useState, useEffect, useMemo } from 'react';
import {
Table,
Card,
PaginationProps,
Button,
Space,
Typography,
} from '@arco-design/web-react';
import PermissionWrapper from '@/components/PermissionWrapper';
import { IconDownload, IconPlus } from '@arco-design/web-react/icon';
import axios from 'axios';
import useLocale from '@/utils/useLocale';
import SearchForm from './form';
import locale from './locale';
import styles from './style/index.module.less';
import './mock';
import { getColumns } from './constants';
const { Title } = Typography;
export const ContentType = ['图文', '横版短视频', '竖版短视频'];
export const FilterType = ['规则筛选', '人工'];
export const Status = ['已上线', '未上线'];
function SearchTable() {
const t = useLocale(locale);
const tableCallback = async (record, type) => {
console.log(record, type);
};
const columns = useMemo(() => getColumns(t, tableCallback), [t]);
const [data, setData] = useState([]);
const [pagination, setPatination] = useState<PaginationProps>({
sizeCanChange: true,
showTotal: true,
pageSize: 10,
current: 1,
pageSizeChangeResetCurrent: true,
});
const [loading, setLoading] = useState(true);
const [formParams, setFormParams] = useState({});
useEffect(() => {
fetchData();
}, [pagination.current, pagination.pageSize, JSON.stringify(formParams)]);
function fetchData() {
const { current, pageSize } = pagination;
setLoading(true);
axios
.get('/api/list', {
params: {
page: current,
pageSize,
...formParams,
},
})
.then((res) => {
setData(res.data.list);
setPatination({
...pagination,
current,
pageSize,
total: res.data.total,
});
setLoading(false);
});
}
function onChangeTable({ current, pageSize }) {
setPatination({
...pagination,
current,
pageSize,
});
}
function handleSearch(params) {
setPatination({ ...pagination, current: 1 });
setFormParams(params);
}
return (
<Card>
<Title heading={6}>{t['menu.list.searchTable']}</Title>
<SearchForm onSearch={handleSearch} />
<PermissionWrapper
requiredPermissions={[
{ resource: 'menu.list.searchTable', actions: ['write'] },
]}
>
<div className={styles['button-group']}>
<Space>
<Button type="primary" icon={<IconPlus />}>
{t['searchTable.operations.add']}
</Button>
<Button>{t['searchTable.operations.upload']}</Button>
</Space>
<Space>
<Button icon={<IconDownload />}>
{t['searchTable.operation.download']}
</Button>
</Space>
</div>
</PermissionWrapper>
<Table
rowKey="id"
loading={loading}
onChange={onChangeTable}
pagination={pagination}
columns={columns}
data={data}
/>
</Card>
);
}
export default SearchTable;

@ -1,52 +0,0 @@
const i18n = {
'en-US': {
'menu.list': 'List',
'menu.list.searchTable': 'Search Table',
'searchTable.form.search': 'Search',
'searchTable.form.reset': 'Reset',
'searchTable.columns.id': 'Collection ID',
'searchTable.columns.name': 'Collection Name',
'searchTable.columns.contentType': 'Content genre',
'searchTable.columns.filterType': 'Filter method',
'searchTable.columns.createdTime': 'Creation time',
'searchTable.columns.status': 'Status',
'searchTable.columns.contentNum': 'Content quantity',
'searchTable.columns.operations': 'Operation',
'searchTable.columns.operations.view': 'View',
'searchTable.columns.operations.update': 'Edit',
'searchTable.columns.operations.offline': 'Offline',
'searchTable.columns.operations.online': 'Online',
'searchTable.operations.add': 'New',
'searchTable.operations.upload': 'Bulk upload',
'searchTable.operation.download': 'Download',
'searchForm.id.placeholder': 'Please enter the collection ID',
'searchForm.name.placeholder': 'Please enter the collection name',
'searchForm.all.placeholder': 'all',
},
'zh-CN': {
'menu.list': '列表页',
'menu.list.searchTable': '查询表格',
'searchTable.form.search': '查询',
'searchTable.form.reset': '重置',
'searchTable.columns.id': '集合编号',
'searchTable.columns.name': '集合名称',
'searchTable.columns.contentType': '内容体裁',
'searchTable.columns.filterType': '筛选方式',
'searchTable.columns.createdTime': '创建时间',
'searchTable.columns.status': '状态',
'searchTable.columns.contentNum': '内容量',
'searchTable.columns.operations': '操作',
'searchTable.columns.operations.view': '查看',
'searchTable.columns.operations.update': '修改',
'searchTable.columns.operations.online': '上线',
'searchTable.columns.operations.offline': '下线',
'searchTable.operations.add': '新建',
'searchTable.operations.upload': '批量导入',
'searchTable.operation.download': '下载',
'searchForm.id.placeholder': '请输入集合编号',
'searchForm.name.placeholder': '请输入集合名称',
'searchForm.all.placeholder': '全部',
},
};
export default i18n;

@ -1,99 +0,0 @@
import Mock from 'mockjs';
import qs from 'query-string';
import dayjs from 'dayjs';
import setupMock from '@/utils/setupMock';
const { list } = Mock.mock({
'list|100': [
{
id: /[0-9]{8}[-][0-9]{4}/,
name: () =>
Mock.Random.pick([
'每日推荐视频集',
'抖音短视频候选集',
'国际新闻集合',
]),
'contentType|0-2': 0,
'filterType|0-1': 0,
'count|0-2000': 0,
'createdTime|1-60': 0,
'status|0-1': 0,
},
],
});
const filterData = (
rest: {
id?: string;
name?: string;
'contentType[]'?: string[];
'filterType[]'?: string[];
'createdTime[]'?: string[];
'status[]'?: string;
} = {}
) => {
const {
id,
name,
'contentType[]': contentType,
'filterType[]': filterType,
'createdTime[]': createdTime,
'status[]': status,
} = rest;
if (id) {
return list.filter((item) => item.id === id);
}
let result = [...list];
if (name) {
result = result.filter((item) => {
return (item.name as string).toLowerCase().includes(name.toLowerCase());
});
}
if (contentType) {
result = result.filter((item) =>
contentType.includes(item.contentType.toString())
);
}
if (filterType) {
result = result.filter((item) =>
filterType.includes(item.filterType.toString())
);
}
if (createdTime && createdTime.length === 2) {
const [begin, end] = createdTime;
result = result.filter((item) => {
const time = dayjs()
.subtract(item.createdTime, 'days')
.format('YYYY-MM-DD HH:mm:ss');
return (
!dayjs(time).isBefore(dayjs(begin)) && !dayjs(time).isAfter(dayjs(end))
);
});
}
if (status && status.length) {
result = result.filter((item) => status.includes(item.status.toString()));
}
return result;
};
setupMock({
setup: () => {
Mock.mock(new RegExp('/api/list'), (params) => {
const {
page = 1,
pageSize = 10,
...rest
} = qs.parseUrl(params.url).query;
const p = page as number;
const ps = pageSize as number;
const result = filterData(rest);
return {
list: result.slice((p - 1) * ps, p * ps),
total: result.length,
};
});
},
});

@ -1,50 +0,0 @@
.toolbar {
display: flex;
justify-content: space-between;
margin-bottom: 24px;
}
.operations {
display: flex;
}
.content-type {
display: flex;
> svg {
margin-right: 8px;
margin-top: 3px;
}
}
.search-form-wrapper {
display: flex;
border-bottom: 1px solid var(--color-border-1);
margin-bottom: 20px;
.right-button {
display: flex;
flex-direction: column;
justify-content: space-between;
padding-left: 20px;
margin-bottom: 20px;
border-left: 1px solid var(--color-border-2);
box-sizing: border-box;
}
}
.button-group {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.search-form {
padding-right: 20px;
:global(.arco-form-label-item-left) {
> label {
white-space: nowrap;
}
}
}

@ -1,164 +0,0 @@
import React, { useEffect, useState } from 'react';
import {
Card,
Steps,
Typography,
Grid,
Space,
Button,
Table,
Badge,
} from '@arco-design/web-react';
import axios from 'axios';
import useLocale from '@/utils/useLocale';
import locale from './locale';
import ProfileItem from './item';
import styles from './style/index.module.less';
import './mock';
function BasicProfile() {
const t = useLocale(locale);
const [loading, setLoading] = useState(false);
const [data, setData] = useState({ status: 1 });
const [preLoading, setPreLoading] = useState(false);
const [preData, setPreData] = useState({});
const [tableLoading, setTableLoading] = useState(false);
const [tableData, setTableData] = useState([]);
function fetchData() {
setLoading(true);
axios
.get('/api/basicProfile')
.then((res) => {
setData(res.data || {});
})
.finally(() => {
setLoading(false);
});
}
function fetchPreData() {
setPreLoading(true);
axios
.get('/api/basicProfile')
.then((res) => {
setPreData(res.data || {});
})
.finally(() => {
setPreLoading(false);
});
}
function fetchTableData() {
setTableLoading(true);
axios
.get('/api/adjustment')
.then((res) => {
setTableData(res.data);
})
.finally(() => {
setTableLoading(false);
});
}
useEffect(() => {
fetchData();
fetchPreData();
fetchTableData();
}, []);
return (
<div className={styles.container}>
<Card>
<Grid.Row justify="space-between" align="center">
<Grid.Col span={16}>
<Typography.Title heading={6}>
{t['basicProfile.title.form']}
</Typography.Title>
</Grid.Col>
<Grid.Col span={8} style={{ textAlign: 'right' }}>
<Space>
<Button>{t['basicProfile.cancel']}</Button>
<Button type="primary">{t['basicProfile.goBack']}</Button>
</Space>
</Grid.Col>
</Grid.Row>
<Steps current={data.status} lineless className={styles.steps}>
<Steps.Step title={t['basicProfile.steps.commit']} />
<Steps.Step title={t['basicProfile.steps.approval']} />
<Steps.Step title={t['basicProfile.steps.finish']} />
</Steps>
</Card>
<ProfileItem
title={t['basicProfile.title.currentParams']}
data={data}
type="current"
loading={loading}
/>
<ProfileItem
title={t['basicProfile.title.originParams']}
data={preData}
type="origin"
loading={preLoading}
/>
<Card>
<Typography.Title heading={6}>
{t['basicProfile.adjustment.record']}
</Typography.Title>
<Table
loading={tableLoading}
data={tableData}
columns={[
{
dataIndex: 'contentId',
title: t['basicProfile.adjustment.contentId'],
},
{
dataIndex: 'content',
title: t['basicProfile.adjustment.content'],
},
{
dataIndex: 'status',
title: t['basicProfile.adjustment.status'],
render: (status) => {
if (status) {
return (
<Badge
status="success"
text={t['basicProfile.adjustment.success']}
/>
);
}
return (
<Badge
status="processing"
text={t['basicProfile.adjustment.waiting']}
/>
);
},
},
{
dataIndex: 'updatedTime',
title: t['basicProfile.adjustment.updatedTime'],
},
{
title: t['basicProfile.adjustment.operation'],
headerCellStyle: { paddingLeft: '15px' },
render() {
return (
<Button type="text">
{t['basicProfile.adjustment.operation.view']}
</Button>
);
},
},
]}
/>
</Card>
</div>
);
}
export default BasicProfile;

@ -1,128 +0,0 @@
import React, { CSSProperties } from 'react';
import useLocale from '@/utils/useLocale';
import { Descriptions, Card, Skeleton } from '@arco-design/web-react';
import locale from './locale';
interface ProfileItemProps {
title: string;
data: any;
style?: CSSProperties;
type: 'origin' | 'current';
loading?: boolean;
}
function ProfileItem(props: ProfileItemProps) {
const t = useLocale(locale);
const { title, data, type, loading } = props;
const blockDataList: {
title: string;
data: {
label: string;
value: string;
}[];
}[] = [];
blockDataList.push({
title: t[`basicProfile.title.${type}Video`],
data: [
{
label: t['basicProfile.label.video.mode'],
value: data?.video?.mode || '-',
},
{
label: t['basicProfile.label.video.acquisition.resolution'],
value: data?.video?.acquisition.resolution || '-',
},
{
label: t['basicProfile.label.video.acquisition.frameRate'],
value: `${data?.video?.acquisition.frameRate || '-'} fps`,
},
{
label: t['basicProfile.label.video.encoding.resolution'],
value: data?.video?.encoding.resolution || '-',
},
{
label: t['basicProfile.label.video.encoding.rate.min'],
value: `${data?.video?.encoding.rate.min || '-'} bps`,
},
{
label: t['basicProfile.label.video.encoding.rate.max'],
value: `${data?.video?.encoding.rate.max || '-'} bps`,
},
{
label: t['basicProfile.label.video.encoding.rate.default'],
value: `${data?.video?.encoding.rate.default || '-'} bps`,
},
{
label: t['basicProfile.label.video.encoding.frameRate'],
value: `${data?.video?.encoding.frameRate || '-'} fpx`,
},
{
label: t['basicProfile.label.video.encoding.profile'],
value: data?.video?.encoding.profile || '-',
},
],
});
blockDataList.push({
title: t[`basicProfile.title.${type}Audio`],
data: [
{
label: t['basicProfile.label.audio.mode'],
value: data?.audio?.mode || '-',
},
{
label: t['basicProfile.label.audio.acquisition.channels'],
value: `${data?.audio?.acquisition.channels || '-'} ${
t['basicProfile.unit.audio.channels']
}`,
},
{
label: t['basicProfile.label.audio.encoding.channels'],
value: `${data?.audio?.encoding.channels || '-'} ${
t['basicProfile.unit.audio.channels']
}`,
},
{
label: t['basicProfile.label.audio.encoding.rate'],
value: `${data?.audio?.encoding.rate || '-'} kbps`,
},
{
label: t['basicProfile.label.audio.encoding.profile'],
value: data?.audio?.encoding.profile || '-',
},
],
});
return (
<Card>
<div>
{blockDataList.map(({ title: blockTitle, data: blockData }, index) => (
<Descriptions
key={`${index}`}
colon=":"
labelStyle={{ textAlign: 'right', width: 200, paddingRight: 10 }}
valueStyle={{ width: 400 }}
title={blockTitle}
data={
loading
? blockData.map((item) => ({
...item,
value: (
<Skeleton
text={{ rows: 1, style: { width: '200px' } }}
animation
/>
),
}))
: blockData
}
style={index > 0 ? { marginTop: '20px' } : {}}
/>
))}
</div>
</Card>
);
}
export default ProfileItem;

@ -1,82 +0,0 @@
const i18n = {
'en-US': {
'menu.profile': 'Profile',
'menu.profile.basic': 'Basic Profile',
'basicProfile.title.form': 'Parameter Approval Process Table',
'basicProfile.steps.commit': 'Commit',
'basicProfile.steps.approval': 'Approval',
'basicProfile.steps.finish': 'Finish',
'basicProfile.title.currentVideo': 'Current Video Parameters',
'basicProfile.title.currentAudio': 'Current Audio Parameters',
'basicProfile.title.originVideo': 'Origin Video Parameters',
'basicProfile.title.originAudio': 'Origin Audio Parameters',
'basicProfile.label.video.mode': 'Config Mode',
'basicProfile.label.video.acquisition.resolution': 'Acquisition Resolution',
'basicProfile.label.video.acquisition.frameRate': 'Acquisition Frame Rate',
'basicProfile.label.video.encoding.resolution': 'Encoding Resolution',
'basicProfile.label.video.encoding.rate.min': 'Encoding Min Rate',
'basicProfile.label.video.encoding.rate.max': 'Encoding Max Rate',
'basicProfile.label.video.encoding.rate.default': 'Encoding Default Rate',
'basicProfile.label.video.encoding.frameRate': 'Encoding Frame Rate',
'basicProfile.label.video.encoding.profile': 'Encoding Profile',
'basicProfile.label.audio.mode': 'Config Mode',
'basicProfile.label.audio.acquisition.channels': 'Acquisition Channels',
'basicProfile.label.audio.encoding.channels': 'Encoding Channels',
'basicProfile.label.audio.encoding.rate': 'Encoding Rate',
'basicProfile.label.audio.encoding.profile': 'Encoding Profile',
'basicProfile.unit.audio.channels': 'channels',
'basicProfile.goBack': 'GoBack',
'basicProfile.cancel': 'Cancel Process',
'basicProfile.adjustment.record': 'Parameter adjustment record',
'basicProfile.adjustment.contentId': 'Content number',
'basicProfile.adjustment.content': 'Adjust content',
'basicProfile.adjustment.status': 'Current state',
'basicProfile.adjustment.updatedTime': 'Change the time',
'basicProfile.adjustment.operation': 'Operation',
'basicProfile.adjustment.success': 'passed',
'basicProfile.adjustment.waiting': 'under review',
'basicProfile.adjustment.operation.view': 'view',
},
'zh-CN': {
'menu.profile': '详情页',
'menu.profile.basic': '基础详情页',
'basicProfile.title.form': '参数审批流程表',
'basicProfile.steps.commit': '提交修改',
'basicProfile.steps.approval': '审批中',
'basicProfile.steps.finish': '修改完成',
'basicProfile.title.currentVideo': '现视频参数',
'basicProfile.title.currentAudio': '现音频参数',
'basicProfile.title.originVideo': '原视频参数',
'basicProfile.title.originAudio': '原音频参数',
'basicProfile.label.video.mode': '配置模式',
'basicProfile.label.video.acquisition.resolution': '采集分辨率',
'basicProfile.label.video.acquisition.frameRate': '采集帧率',
'basicProfile.label.video.encoding.resolution': '编码分辨率',
'basicProfile.label.video.encoding.rate.min': '编码码率最小值',
'basicProfile.label.video.encoding.rate.max': '编码码率最大值',
'basicProfile.label.video.encoding.rate.default': '编码码率默认值',
'basicProfile.label.video.encoding.frameRate': '编码帧率',
'basicProfile.label.video.encoding.profile': '编码profile',
'basicProfile.label.audio.mode': '配置模式',
'basicProfile.label.audio.acquisition.channels': '采集声道数',
'basicProfile.label.audio.encoding.channels': '编码声道数',
'basicProfile.label.audio.encoding.rate': '编码码率',
'basicProfile.label.audio.encoding.profile': '编码 profile',
'basicProfile.unit.audio.channels': '声道',
'basicProfile.goBack': '返回',
'basicProfile.cancel': '取消流程',
'basicProfile.adjustment.record': '参数调整记录',
'basicProfile.adjustment.contentId': '内容编号',
'basicProfile.adjustment.content': '调整内容',
'basicProfile.adjustment.status': '当前状态',
'basicProfile.adjustment.updatedTime': '修改时间',
'basicProfile.adjustment.operation': '操作',
'basicProfile.adjustment.success': '已通过',
'basicProfile.adjustment.waiting': '审核中',
'basicProfile.adjustment.operation.view': '查看',
},
};
export default i18n;

@ -1,52 +0,0 @@
import Mock from 'mockjs';
import setupMock from '@/utils/setupMock';
setupMock({
setup: () => {
Mock.mock(new RegExp('/api/basicProfile'), () => {
return {
status: 2,
video: {
mode: '自定义',
acquisition: {
resolution: '720*1280',
frameRate: 15,
},
encoding: {
resolution: '720*1280',
rate: {
min: 300,
max: 800,
default: 1500,
},
frameRate: 15,
profile: 'high',
},
},
audio: {
mode: '自定义',
acquisition: {
channels: 8,
},
encoding: {
channels: 8,
rate: 128,
profile: 'ACC-LC',
},
},
};
});
Mock.mock(new RegExp('/api/adjustment'), () => {
return new Array(2).fill('0').map(() => ({
contentId: `${Mock.Random.pick([
'视频类',
'音频类',
])}${Mock.Random.natural(1000, 9999)}`,
content: '视频参数变更,音频参数变更',
status: Mock.Random.natural(0, 1),
updatedTime: Mock.Random.datetime('yyyy-MM-dd HH:mm:ss'),
}));
});
},
});

@ -1,12 +0,0 @@
.container {
:global(.arco-card) {
margin-top: 16px;
}
}
.steps {
max-width: 548px;
margin: 0 auto;
margin-top: 8px;
margin-bottom: 30px;
}

@ -1,53 +0,0 @@
import React from 'react';
import { Typography, Result, Button, Link } from '@arco-design/web-react';
import { IconLink } from '@arco-design/web-react/icon';
import useLocale from '@/utils/useLocale';
import locale from './locale';
import styles from './style/index.module.less';
function Success() {
const t = useLocale(locale);
return (
<div>
<div className={styles.wrapper}>
<Result
className={styles.result}
status="error"
title={t['error.result.title']}
subTitle={t['error.result.subTitle']}
extra={[
<Button key="again" type="secondary" style={{ marginRight: 16 }}>
{t['error.result.goBack']}
</Button>,
<Button key="back" type="primary">
{t['error.result.retry']}
</Button>,
]}
/>
<div className={styles['details-wrapper']}>
<Typography.Title heading={6} style={{ marginTop: 0 }}>
{t['error.detailTitle']}
</Typography.Title>
<Typography.Paragraph style={{ marginBottom: 0 }}>
<ol>
<li>
{t['error.detailLine.record']}
<Link suppressHydrationWarning>
<IconLink />
{t['error.detailLine.record.link']}
</Link>
</li>
<li>
{t['error.detailLine.auth']}
<Link suppressHydrationWarning>{t['error.detailLine.auth.link']}</Link>
</li>
</ol>
</Typography.Paragraph>
</div>
</div>
</div>
);
}
export default Success;

@ -1,33 +0,0 @@
const i18n = {
'en-US': {
'menu.result': 'Result',
'menu.result.error': 'Error',
'error.result.title': 'Submit Error',
'error.result.subTitle':
'Please check the modified information and try again',
'error.result.goBack': 'GoBack',
'error.result.retry': 'Retry',
'error.detailTitle': 'Details of Error',
'error.detailLine.record':
'The current domain name has not been registered, please check the registration process: ',
'error.detailLine.record.link': 'Registration Process',
'error.detailLine.auth':
'Your user group does not have the authority to perform this operation;',
'error.detailLine.auth.link': 'Request for access',
},
'zh-CN': {
'menu.result': '结果页',
'menu.result.error': '失败页',
'error.result.title': '提交失败',
'error.result.subTitle': '请核对修改信息后,再重试',
'error.result.goBack': '回到首页',
'error.result.retry': '返回修改',
'error.detailTitle': '错误详情',
'error.detailLine.record': '当前域名未备案,备案流程请查看:',
'error.detailLine.record.link': '备案流程',
'error.detailLine.auth': '你的用户组不具有进行此操作的权限;',
'error.detailLine.auth.link': '申请权限',
},
};
export default i18n;

@ -1,18 +0,0 @@
.wrapper {
padding: 24px 150px;
background-color: var(--color-bg-2);
box-sizing: border-box;
min-height: calc(100vh - 168px);
}
.result {
margin: 150px 0 36px;
}
.details-wrapper {
width: 100%;
padding: 20px;
background-color: var(--color-fill-2);
box-sizing: border-box;
margin-bottom: 150px;
}

@ -1,61 +0,0 @@
import React from 'react';
import { Typography, Result, Button, Steps } from '@arco-design/web-react';
import useLocale from '@/utils/useLocale';
import locale from './locale';
import styles from './style/index.module.less';
const Step = Steps.Step;
function Success() {
const t = useLocale(locale);
return (
<div>
<div className={styles.wrapper}>
<Result
className={styles.result}
status="success"
title={t['success.result.title']}
subTitle={t['success.result.subTitle']}
extra={[
<Button key="again" type="secondary" style={{ marginRight: 16 }}>
{t['success.result.printResult']}
</Button>,
<Button key="back" type="primary">
{t['success.result.projectList']}
</Button>,
]}
/>
<div className={styles['steps-wrapper']}>
<Typography.Paragraph bold>
{t['success.result.progress']}
</Typography.Paragraph>
<Steps type="dot" current={2}>
<Step
title={t['success.submitApplication']}
description="2020/10/10 14:00:39"
/>
<Step
title={t['success.leaderReview']}
description={t['success.processing']}
/>
<Step
title={t['success.purchaseCertificate']}
description={t['success.waiting']}
/>
<Step
title={t['success.safetyTest']}
description={t['success.waiting']}
/>
<Step
title={t['success.launched']}
description={t['success.waiting']}
/>
</Steps>
</div>
</div>
</div>
);
}
export default Success;

@ -1,36 +0,0 @@
const i18n = {
'en-US': {
'menu.result': 'Result',
'menu.result.success': 'Success',
'success.result.title': 'Submit Success',
'success.result.subTitle': 'Submit form success!',
'success.result.printResult': 'Print result',
'success.result.projectList': 'Project List',
'success.result.progress': 'Progress',
'success.submitApplication': 'Submit Application',
'success.leaderReview': 'Leader Review',
'success.purchaseCertificate': 'Purchase Certificate',
'success.safetyTest': 'Safety Test',
'success.launched': 'Officially launched',
'success.waiting': 'Waiting',
'success.processing': 'Processing',
},
'zh-CN': {
'menu.result': '结果页',
'menu.result.success': '成功页',
'success.result.title': '提交成功',
'success.result.subTitle': '表单提交成功!',
'success.result.printResult': '打印结果',
'success.result.projectList': '返回项目列表',
'success.result.progress': '当前进度',
'success.submitApplication': '提交申请',
'success.leaderReview': '直属领导审核',
'success.purchaseCertificate': '购买证书',
'success.safetyTest': '安全测试',
'success.launched': '正式上线',
'success.waiting': '未开始',
'success.processing': '进行中',
},
};
export default i18n;

@ -1,19 +0,0 @@
.wrapper {
padding: 24px 150px;
background-color: var(--color-bg-2);
box-sizing: border-box;
min-height: calc(100vh - 168px);
}
.result {
margin: 150px 0 36px;
}
.steps-wrapper {
width: 100%;
min-width: fit-content;
padding: 20px;
background-color: var(--color-fill-2);
box-sizing: border-box;
margin-bottom: 150px;
}
Loading…
Cancel
Save