fixed: ts build error
This commit is contained in:
parent
4d5449364a
commit
1acdc2a99d
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import {Popconfirm, Space} from "antd";
|
||||
import {Popconfirm} from "antd";
|
||||
|
||||
import {IconAdd, IconDelete} from "@/components/icons";
|
||||
import ImageList from "@/components/article/list.tsx";
|
||||
@ -10,7 +10,7 @@ import styles from './article.module.scss'
|
||||
|
||||
type Props = {
|
||||
children?: React.ReactNode;
|
||||
index?: number;
|
||||
index: number;
|
||||
className?: string;
|
||||
blocks: BlockContent[];
|
||||
editable?: boolean;
|
||||
@ -51,22 +51,6 @@ export default function ArticleBlock(
|
||||
errorMessage
|
||||
}: Props) {
|
||||
const blocks = rebuildBlockArray(defaultBlocks)
|
||||
const handleBlockRemove = (index: number) => {
|
||||
// 删除当前项
|
||||
onChange?.(blocks.filter((_, idx) => index !== idx))
|
||||
}
|
||||
const firstTextBlockIndex = blocks.findIndex(it => it.type === 'text')
|
||||
// 新增
|
||||
const handleAddBlock = (type: 'text' | 'image', insertIndex: number = -1) => {
|
||||
const newBlock: BlockContent = type === 'text' ? {type: 'text', content: ''} : {type: 'image', content: ''};
|
||||
const _blocks = [...blocks]
|
||||
if (insertIndex == -1 || insertIndex >= blocks.length) { // -1或者越界表示新增
|
||||
_blocks.push(newBlock)
|
||||
} else {
|
||||
_blocks.splice(insertIndex, 0, newBlock)
|
||||
}
|
||||
onChange?.(_blocks)
|
||||
}
|
||||
|
||||
const handleBlockChange = (index: number, block: BlockContent) => {
|
||||
const _blocks = [...blocks]
|
||||
|
@ -39,7 +39,7 @@ export default function ArticleEditModal(props: Props) {
|
||||
}
|
||||
const save = props.type == 'news' ? article.save : regenerate
|
||||
setState({loading: true})
|
||||
save(title, groups, props.id > 0 ? props.id : undefined).then(() => {
|
||||
save(title, groups, props.id && props.id > 0 ? props.id : undefined).then(() => {
|
||||
props.onClose?.(true)
|
||||
}).catch(e=>{
|
||||
setState({error: e.data || '保存失败,请重试!'})
|
||||
@ -65,7 +65,7 @@ export default function ArticleEditModal(props: Props) {
|
||||
|
||||
return (<Modal
|
||||
title={'编辑文章'}
|
||||
open={props.id >= 0}
|
||||
open={!!props.id && props.id >= 0}
|
||||
maskClosable={false}
|
||||
keyboard={false}
|
||||
width={800}
|
||||
|
@ -14,7 +14,7 @@ type Props = {
|
||||
|
||||
function pushBlocksToGroup(blocks: BlockContent[],groups: BlockContent[][]){
|
||||
const lastGroup = groups[groups.length - 1]
|
||||
if (lastGroup && lastGroup.filter(s=>s.type == 'text') == 0) {
|
||||
if (lastGroup && lastGroup.filter(s=>s.type == 'text').length == 0) {
|
||||
// 如果上一个group中没有文本则直接合并
|
||||
lastGroup.push(...blocks)
|
||||
} else {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, {useState} from "react";
|
||||
import {Input, Popconfirm, Spin, Upload, UploadProps} from "antd";
|
||||
import {CloseOutlined,CloudUploadOutlined} from "@ant-design/icons";
|
||||
import {CloseOutlined} from "@ant-design/icons";
|
||||
import {clsx} from "clsx";
|
||||
|
||||
import styles from './article.module.scss'
|
||||
|
@ -1,5 +1,3 @@
|
||||
import React from "react";
|
||||
|
||||
import {BlockImage} from "@/components/article/item.tsx";
|
||||
|
||||
import styles from './article.module.scss'
|
||||
|
@ -2,13 +2,14 @@ import React, {useState} from "react";
|
||||
import {Button, Modal} from "antd";
|
||||
import {ButtonType} from "antd/es/button";
|
||||
import {showErrorToast, showToast} from "@/components/message.ts";
|
||||
import {BizError} from "@/service/types.ts";
|
||||
|
||||
type Props = {
|
||||
selected: any[],
|
||||
type?: ButtonType;
|
||||
emptyMessage: string,
|
||||
confirmMessage: React.ReactNode,
|
||||
onProcess: (ids: Id[]) => Promise<void>
|
||||
onProcess: (ids: Id[]) => Promise<any|void>
|
||||
successMessage?: string;
|
||||
onSuccess?: () => void;
|
||||
children?: React.ReactNode
|
||||
@ -32,7 +33,7 @@ export default function ButtonBatch(
|
||||
onSuccess()
|
||||
}
|
||||
} catch (e) {
|
||||
showErrorToast(e)
|
||||
showErrorToast(e as unknown as BizError)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import {useSortable} from "@dnd-kit/sortable";
|
||||
import {useSetState} from "ahooks";
|
||||
import React, {useEffect} from "react";
|
||||
import {clsx} from "clsx";
|
||||
import {Image, Popconfirm} from "antd";
|
||||
import {Popconfirm} from "antd";
|
||||
import {CheckCircleFilled, MenuOutlined, MinusCircleFilled} from "@ant-design/icons";
|
||||
|
||||
import ImageCover from '@/assets/images/cover.png'
|
||||
@ -51,7 +51,7 @@ export const VideoListItem = (
|
||||
className={`video-item-info flex gap-2 flex-1 bg-gray-100 h-[80px] overflow-hidden rounded-lg p-3 shadow-blue-500 ${active ? 'video-item-shadow' : ''}`}>
|
||||
<div className={'video-title leading-7 flex-1'}>{video.title || video.video_title}</div>
|
||||
<div className={'video-item-cover bg-white rounded-md overflow-hidden'}>
|
||||
<img className="w-[100px] h-[56px] object-cover" src={video.cover || ImageCover} alt={video.video_title}/>
|
||||
<img className="w-[100px] h-[56px] object-cover" src={video.cover || ImageCover} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="operation flex items-center ml-2 gap-3 text-lg text-gray-400">
|
||||
|
@ -2,19 +2,10 @@ import React, {createContext, useEffect, useReducer} from "react";
|
||||
|
||||
import Loader from "@/components/loader";
|
||||
import {getAuthToken, setAuthToken} from "@/hooks/useAuth.ts";
|
||||
import {auth, getUserInfo} from "@/service/api/user.ts";
|
||||
|
||||
import {auth} from "@/service/api/user.ts";
|
||||
|
||||
const UserRoleStorageKey = 'user-current-role';
|
||||
|
||||
function getCurrentRole() {
|
||||
return (localStorage.getItem(UserRoleStorageKey)) as UserRole
|
||||
}
|
||||
|
||||
export function setCurrentRole(role: UserRole) {
|
||||
localStorage.setItem(UserRoleStorageKey, role)
|
||||
}
|
||||
|
||||
function removeRoleStorage() {
|
||||
localStorage.removeItem(UserRoleStorageKey)
|
||||
}
|
||||
@ -87,7 +78,7 @@ export const AuthProvider = ({children}: { children: React.ReactNode }) => {
|
||||
}
|
||||
// 登出
|
||||
const logout = async () => {
|
||||
setAuthToken(null)
|
||||
setAuthToken(null,null,-1)
|
||||
removeRoleStorage()
|
||||
dispatch({
|
||||
action: 'logout',
|
||||
|
@ -18,7 +18,7 @@ const clearAuth = () => {
|
||||
localStorage.removeItem(AppConfig.AUTH_TOKEN_KEY);
|
||||
localStorage.removeItem(AppConfig.AUTHED_PERSON_DATA_KEY);
|
||||
}
|
||||
export const setAuthToken = (token: string | null,profileData:UserProfile, expiry_time = -1) => {
|
||||
export const setAuthToken = (token: string | null,profileData:UserProfile|null, expiry_time = -1) => {
|
||||
if (!token) {
|
||||
clearAuth();
|
||||
return;
|
||||
|
@ -1,4 +1,3 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
|
||||
import App from './App.tsx'
|
||||
|
@ -2,7 +2,6 @@ import {Button, Modal} from "antd";
|
||||
|
||||
import {Player} from "@/components/video/player.tsx";
|
||||
|
||||
import { ArticleGroupList } from "@/_local/mock-data";
|
||||
import ArticleGroup from "@/components/article/group";
|
||||
|
||||
type Props = {
|
||||
@ -31,7 +30,7 @@ export default function VideoDetail({video, onClose}: Props) {
|
||||
<span>标题: xxxxxxxx</span>
|
||||
</div>
|
||||
<div className="content-container max-h-[500px] overflow-auto pr-1 mt-4">
|
||||
<ArticleGroup groups={ArticleGroupList}/>
|
||||
<ArticleGroup groups={[]}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,122 +0,0 @@
|
||||
import React, {useState} from 'react';
|
||||
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
||||
import {
|
||||
DndContext,
|
||||
closestCenter,
|
||||
KeyboardSensor,
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from '@dnd-kit/core';
|
||||
|
||||
import {
|
||||
useSortable, arrayMove,
|
||||
SortableContext,
|
||||
sortableKeyboardCoordinates,
|
||||
verticalListSortingStrategy,
|
||||
} from '@dnd-kit/sortable';
|
||||
|
||||
type TestData = {
|
||||
id: number;
|
||||
}
|
||||
type SortableItemProps = {
|
||||
data: TestData;
|
||||
active?: boolean;
|
||||
id: number;
|
||||
}
|
||||
|
||||
function SortableItem(props: SortableItemProps) {
|
||||
const {
|
||||
attributes,
|
||||
listeners,
|
||||
setNodeRef,
|
||||
transform,
|
||||
transition,
|
||||
} = useSortable({
|
||||
resizeObserverConfig: {},
|
||||
id: props.data.id
|
||||
});
|
||||
|
||||
return (
|
||||
<div ref={setNodeRef} style={{
|
||||
transform: `translateY(${transform ? transform?.y:0}px)`,
|
||||
transition,
|
||||
// marginTop:10,
|
||||
// marginBottom:10
|
||||
}} className={props.active ? 'drop-shadow shadow-blue-400 drop-shadow-md' : ''}>
|
||||
<div className="h-[100px] mb-5 border p-5 rounded bg-white flex justify-between items-center">
|
||||
<div className="flex-1">
|
||||
<div>
|
||||
{JSON.stringify(props.data)}
|
||||
</div>
|
||||
<div>{JSON.stringify(transform)}</div>
|
||||
</div>
|
||||
<button {...attributes} {...listeners} className="cursor-move">Move</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function SortDemo() {
|
||||
const [items, setItems] = useState<TestData[]>([
|
||||
{id: 1},
|
||||
{id: 2},
|
||||
{id: 3},
|
||||
{id: 4},
|
||||
{id: 5},
|
||||
]);
|
||||
const [activeId, setActiveId] = useState<number>();
|
||||
|
||||
function handleDragEnd(event) {
|
||||
const {active, over} = event;
|
||||
setActiveId(undefined)
|
||||
console.log(JSON.stringify({
|
||||
items,
|
||||
active: active.id,
|
||||
over: over.id,
|
||||
}))
|
||||
if (active.id !== over.id) {
|
||||
setItems((items) => {
|
||||
const oldIndex = items.findIndex(s=>s.id == active.id);
|
||||
const newIndex = items.findIndex(s=>s.id == over.id);
|
||||
const _newArr = arrayMove(items, oldIndex, newIndex);
|
||||
console.log(JSON.stringify({
|
||||
_newArr,
|
||||
items,
|
||||
oldIndex,
|
||||
newIndex
|
||||
}))
|
||||
return _newArr;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// const sensors = useSensors(
|
||||
// useSensor(PointerSensor),
|
||||
// useSensor(KeyboardSensor, {
|
||||
// coordinateGetter: sortableKeyboardCoordinates,
|
||||
// })
|
||||
// );
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>{JSON.stringify(items)}</div>
|
||||
<DndContext
|
||||
modifiers={[restrictToVerticalAxis]}
|
||||
onDragEnd={handleDragEnd}
|
||||
onDragStart={e => {
|
||||
if (e.active && e.active.id) {
|
||||
setActiveId(Number(e.active.id))
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SortableContext
|
||||
items={items}
|
||||
>
|
||||
{items.map(it => <SortableItem active={it.id == activeId} key={it.id} data={it} id={it.id}/>)}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
@ -139,7 +139,7 @@ export default function LiveIndex() {
|
||||
return clearAllTimer;
|
||||
}, [])
|
||||
|
||||
const processDeleteVideo = async (ids: number[]) => {
|
||||
const processDeleteVideo = async (ids: Id[]) => {
|
||||
deleteByIds(ids).then(() => {
|
||||
showToast('删除成功!', 'success')
|
||||
loadList()
|
||||
|
@ -4,63 +4,63 @@ import React, {useEffect, useMemo} from "react";
|
||||
|
||||
const prevSelectValues: Id[][] = [];
|
||||
|
||||
function buildValues(options: OptionItem[], selectedValues: Id[][], allValue = -1) {
|
||||
const values: Id[][] = []
|
||||
selectedValues.forEach(item => {
|
||||
if (item.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (item.length == 1) {
|
||||
if (item[0] == allValue) {
|
||||
values.push([allValue]);
|
||||
return;
|
||||
}
|
||||
// 只有1个值 表示选择了一级分类下的所有二级分类
|
||||
const op = options.find(option => option.value === item[0]);
|
||||
if (!op || !op.children || op.children.length === 0) {
|
||||
// 没有找到或者没有二级分类
|
||||
return;
|
||||
}
|
||||
// 只有一级分类
|
||||
op.children.forEach(child => {
|
||||
values.push([item[0], child.value]);
|
||||
})
|
||||
return;
|
||||
}
|
||||
values.push(item)
|
||||
})
|
||||
return values
|
||||
}
|
||||
// function buildValues(options: OptionItem[], selectedValues: Id[][], allValue = -1) {
|
||||
// const values: Id[][] = []
|
||||
// selectedValues.forEach(item => {
|
||||
// if (item.length === 0) {
|
||||
// return;
|
||||
// }
|
||||
// if (item.length == 1) {
|
||||
// if (item[0] == allValue) {
|
||||
// values.push([allValue]);
|
||||
// return;
|
||||
// }
|
||||
// // 只有1个值 表示选择了一级分类下的所有二级分类
|
||||
// const op = options.find(option => option.value === item[0]);
|
||||
// if (!op || !op.children || op.children.length === 0) {
|
||||
// // 没有找到或者没有二级分类
|
||||
// return;
|
||||
// }
|
||||
// // 只有一级分类
|
||||
// op.children.forEach(child => {
|
||||
// values.push([item[0], child.value]);
|
||||
// })
|
||||
// return;
|
||||
// }
|
||||
// values.push(item)
|
||||
// })
|
||||
// return values
|
||||
// }
|
||||
|
||||
// 获取两个数组的差集
|
||||
function getValuesDiff(values: Id[][], prevValues: Id[][]) {
|
||||
if (values.length != prevValues.length) {
|
||||
const moreItems = values.length > prevValues.length ? values : prevValues;
|
||||
const lessItems = values.length > prevValues.length ? prevValues : values;
|
||||
const lessItemsKeys = lessItems.map(s => s.join('-'));
|
||||
for (let i = 0; i < moreItems.length; i++) {
|
||||
const item = moreItems[i], index = lessItemsKeys.indexOf(item.join('-'));
|
||||
if (index === -1) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getAllValue(options: OptionItem[]) {
|
||||
const values: Id[][] = []
|
||||
options.forEach(option => {
|
||||
if (option.children && option.children.length > 0) {
|
||||
option.children.forEach(child => {
|
||||
values.push([option.value, child.value]);
|
||||
})
|
||||
} else {
|
||||
values.push([option.value]);
|
||||
}
|
||||
})
|
||||
return values
|
||||
}
|
||||
// function getValuesDiff(values: Id[][], prevValues: Id[][]) {
|
||||
// if (values.length != prevValues.length) {
|
||||
// const moreItems = values.length > prevValues.length ? values : prevValues;
|
||||
// const lessItems = values.length > prevValues.length ? prevValues : values;
|
||||
// const lessItemsKeys = lessItems.map(s => s.join('-'));
|
||||
// for (let i = 0; i < moreItems.length; i++) {
|
||||
// const item = moreItems[i], index = lessItemsKeys.indexOf(item.join('-'));
|
||||
// if (index === -1) {
|
||||
// return item;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// function getAllValue(options: OptionItem[]) {
|
||||
// const values: Id[][] = []
|
||||
// options.forEach(option => {
|
||||
// if (option.children && option.children.length > 0) {
|
||||
// option.children.forEach(child => {
|
||||
// values.push([option.value, child.value]);
|
||||
// })
|
||||
// } else {
|
||||
// values.push([option.value]);
|
||||
// }
|
||||
// })
|
||||
// return values
|
||||
// }
|
||||
|
||||
export default function ArticleCascader(props: {
|
||||
options: OptionItem[];
|
||||
@ -71,9 +71,9 @@ export default function ArticleCascader(props: {
|
||||
// 清除上一次的选中值
|
||||
prevSelectValues.length = 0;
|
||||
}, [])
|
||||
const allOptionValue = useMemo(() => {
|
||||
return getAllValue(props.options)
|
||||
}, [props.options])
|
||||
// const allOptionValue = useMemo(() => {
|
||||
// return getAllValue(props.options)
|
||||
// }, [props.options])
|
||||
|
||||
const setSelectValues = (value: Id[][]) => {
|
||||
_setSelectValues(value)
|
||||
|
@ -1,13 +1,14 @@
|
||||
import {Button, Pagination, Table, TableColumnsType, TableProps, Typography} from "antd";
|
||||
|
||||
import {Card} from "@/components/card";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import React, {useState} from "react";
|
||||
import {useRequest} from "ahooks";
|
||||
import {formatTime} from "@/util/strings.ts";
|
||||
import ArticleEditModal from "@/components/article/edit-modal.tsx";
|
||||
import {getList} from "@/service/api/article.ts";
|
||||
import EditSearchForm from "@/pages/news/components/edit-search-form.tsx";
|
||||
import ButtonPush2Video from "@/pages/news/components/button-push2video.tsx";
|
||||
import {Key} from "antd/es/table/interface";
|
||||
|
||||
|
||||
export default function NewEdit() {
|
||||
@ -55,8 +56,8 @@ export default function NewEdit() {
|
||||
];
|
||||
|
||||
const rowSelection: TableProps<ListArticleItem>['rowSelection'] = {
|
||||
onChange: (selectedRowKeys: Id[]) => {
|
||||
setSelectedRowKeys(selectedRowKeys)
|
||||
onChange: (selectedRowKeys: Key[]) => {
|
||||
setSelectedRowKeys(selectedRowKeys as Id[])
|
||||
},
|
||||
};
|
||||
|
||||
@ -75,7 +76,7 @@ export default function NewEdit() {
|
||||
bordered
|
||||
pagination={false}
|
||||
/>
|
||||
{data?.pagination.total > 0 && <div className="footer flex justify-between items-center mt-5">
|
||||
{data?.pagination && data?.pagination.total > 0 && <div className="footer flex justify-between items-center mt-5">
|
||||
<Pagination
|
||||
current={params.pagination.page}
|
||||
total={data?.pagination.total}
|
||||
|
@ -20,7 +20,7 @@ export default function NewsIndex() {
|
||||
limit: 10
|
||||
}
|
||||
})
|
||||
const [checkedId, setCheckedId] = useState<number[]>([])
|
||||
const [checkedId, setCheckedId] = useState<Id[]>([])
|
||||
const [activeNews, setActiveNews] = useState<NewsInfo>()
|
||||
|
||||
const [state, setState] = useState<{
|
||||
@ -66,7 +66,7 @@ export default function NewsIndex() {
|
||||
<Checkbox checked={state.checkAll} onChange={e => {
|
||||
setState({checkAll: e.target.checked})
|
||||
if (e.target.checked) {
|
||||
setCheckedId(data.list.map(item => item.id))
|
||||
setCheckedId(data?.list?.map(item => item.id) || [])
|
||||
} else {
|
||||
setCheckedId([])
|
||||
}
|
||||
@ -118,7 +118,7 @@ export default function NewsIndex() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
{data?.pagination.total > 0 ? <div className="flex justify-center mt-10">
|
||||
{data?.pagination && data?.pagination.total > 0 ? <div className="flex justify-center mt-10">
|
||||
<Pagination
|
||||
current={params.pagination.page}
|
||||
total={data?.pagination.total}
|
||||
|
@ -85,7 +85,7 @@ export default function FormLogin() {
|
||||
<Form.Item>
|
||||
<Button disabled={disabled || loading} loading={loading} type="primary" size={'large'} htmlType="submit"
|
||||
block shape={'round'}>
|
||||
{login ? '登录中' : '立即登录'}
|
||||
{loading ? '登录中...' : '立即登录'}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
@ -2,7 +2,6 @@ import axios from 'axios';
|
||||
import {stringify} from 'qs'
|
||||
import {BizError} from './types';
|
||||
import {getAuthToken} from "@/hooks/useAuth.ts";
|
||||
import {showToast} from "@/components/message.ts";
|
||||
|
||||
const JSON_FORMAT: string = 'application/json';
|
||||
const REQUEST_TIMEOUT = 300000; // 超时时长5min
|
||||
|
4
src/types/api.d.ts
vendored
4
src/types/api.d.ts
vendored
@ -82,6 +82,7 @@ declare interface ListCrawlerNewsItem extends BasicArticleInfo {
|
||||
}
|
||||
declare interface VideoInfo {
|
||||
id: number;
|
||||
video_title: string;
|
||||
title: string;
|
||||
cover: string;
|
||||
oss_video_url: string;
|
||||
@ -92,6 +93,7 @@ declare interface VideoInfo {
|
||||
// room live
|
||||
declare interface LiveVideoInfo {
|
||||
id: number;
|
||||
title: string;
|
||||
video_id: number;
|
||||
video_title: string;
|
||||
cover: string;
|
||||
@ -103,5 +105,5 @@ declare interface LiveVideoInfo {
|
||||
|
||||
declare interface LiveState{
|
||||
id: number;
|
||||
live_start_time?: number;
|
||||
live_start_time: number;
|
||||
}
|
||||
|
@ -21,7 +21,9 @@
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedLocals": false,
|
||||
"noImplicitAny": false,
|
||||
"noUnusedParameters": false,
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["src"],
|
||||
|
Loading…
x
Reference in New Issue
Block a user