feat: 根据所有者、类型获取图文集和内容。

2.0/email-builder
Jimmy Liow 11 months ago
parent bfe9c79bd9
commit 128fb346b3

@ -1,4 +1,4 @@
import React, { ReactNode } from 'react'
import { ReactNode } from 'react'
export type ConditionalProps = {
/**
@ -15,6 +15,10 @@ export type ConditionalProps = {
whenFalse: ReactNode
}
export function Conditional({ condition, whenFalse, whenTrue }: ConditionalProps) {
return condition ? whenTrue : whenFalse;
}
export function Conditional({
condition,
whenFalse,
whenTrue,
}: ConditionalProps) {
return condition ? whenTrue : whenFalse
}

@ -8,22 +8,59 @@ const useSnippetStore = create(devtools((set, get) => ({
ownerList: [],
typeList: [],
snippetList: [],
drawerOpen: false,
openDrawer: () => {
set(() => ({
drawerOpen: true
}))
},
closeDrawer: () => {
set(() => ({
drawerOpen: false
}))
},
fetchParamList: async () => {
let fetchOwnerUrl = `${API_HOST}/v2/GetAutoDocParameters`
const fetchOwnerUrl = `${API_HOST}/v2/GetAutoDocParameters`
const params = {};
return fetchJSON(fetchOwnerUrl, params)
.then(json => {
if (json.errcode === 0) {
console.info(json)
const mapTypeList = json?.result?.type.map(item => {
return { value: item.vsn, label: item.vname }
})
mapTypeList.unshift({ value: '', label: '全部' })
set(() => ({
ownerList: json?.result?.owner.map(item => {
return { value: item.vsn, label: item.vname }
}),
typeList: json?.result?.type.map(item => {
return { value: item.vsn, label: item.vname }
})
typeList: mapTypeList
}))
} else {
throw new Error(json?.errmsg + ': ' + json.errcode)
}
})
},
fetchSnippetList: async (formValues) => {
const fetchSnippetListUrl = `${API_HOST}/v2/QueryAutoDocInfo`
const params = {owner: '1/1', type: '234004', title: '中国'};
return fetchJSON(fetchSnippetListUrl, formValues)
.then(json => {
if (json.errcode === 0) {
console.info(json)
set(() => ({
snippetList: json?.result
// ownerList: json?.result?.owner.map(item => {
// return { value: item.vsn, label: item.vname }
// }),
}))
} else {
throw new Error(json?.errmsg + ': ' + json.errcode)
@ -31,6 +68,22 @@ const useSnippetStore = create(devtools((set, get) => ({
})
},
fetchSnippetDetail: async (snippetId) => {
const fetchSnippetDetailUrl = `${API_HOST}/v2/GetAutoDocInfoDetail`
const params = {adi_sn: snippetId};
return fetchJSON(fetchSnippetDetailUrl, params)
.then(json => {
if (json.errcode === 0 && json?.result.length > 0) {
console.info(json)
return json?.result[0].adi_content
} else {
throw new Error(json?.errmsg + ': ' + json.errcode)
}
})
},
}), { name: 'snippetStore' }))
export default useSnippetStore

@ -1,4 +1,5 @@
import useAuthStore from '@/stores/AuthStore'
import useSnippetStore from '@/stores/SnippetStore'
import useConversationStore from '@/stores/ConversationStore'
import { useThemeContext } from '@/stores/ThemeContext'
import { DownOutlined } from '@ant-design/icons'
@ -40,11 +41,19 @@ function DesktopApp() {
const totalNotify = useConversationStore((state) => state.totalNotify)
const [drawerOpen, setDrawerOpen] = useState(false)
const [
openDrawer,
closeDrawer,
drawerOpen,
] = useSnippetStore((state) => [
state.openDrawer,
state.closeDrawer,
state.drawerOpen,
])
const onClick = ({ key }) => {
if (key === 'snippet-list') {
setDrawerOpen(true)
openDrawer()
}
}
@ -101,8 +110,9 @@ function DesktopApp() {
title='图文集管理'
placement={'top'}
size={'large'}
onClose={() => setDrawerOpen(false)}
open={drawerOpen}>
onClose={() => closeDrawer()}
open={drawerOpen}
>
<SnippetList></SnippetList>
</Drawer>
<Row gutter={{ md: 24 }} align='middle'>

@ -0,0 +1,61 @@
import { Empty, Skeleton, Divider, Flex, Button } from 'antd'
import { Conditional } from '@/components/Conditional'
import { isEmpty, isNotEmpty } from '@/utils/commons'
const decodeHtml = (text) => {
if (isEmpty(text)) return
const temp = document.createElement('div')
temp.innerHTML = text
return temp.innerText || temp.textContent
}
const HtmlPreview = (props) => {
const { loading = false, value } = props
const html = decodeHtml(value)
if (loading) {
return <Skeleton className='p-6' active />
}
return (
<div className='border-solid border rounded border-gray-300'>
<Conditional
condition={isNotEmpty(html)}
whenTrue={
<pre className='whitespace-pre-wrap break-words ps-6 pe-6'>
{html}
</pre>
}
whenFalse={<Empty className='p-6' description={false} />}
/>
<Divider />
<Flex gap='middle' justify='flex-end' wrap className='p-6'>
<Button
onClick={() => {
// setSnippetModalOpen(true)
}}>
编辑
</Button>
<Button
onClick={() => {
//
}}>
复制
</Button>
<Button
danger
onClick={() => {
//
}}>
删除
</Button>
</Flex>
</div>
)
}
export default HtmlPreview

@ -9,28 +9,42 @@ import {
Button,
Space,
Modal,
Select
Select,
Divider,
Empty,
} from 'antd'
import { useState, useRef, useEffect } from 'react'
import LexicalEditorInput from './LexicalEditorInput'
import HtmlPreview from './HtmlPreview'
import useSnippetStore from '@/stores/SnippetStore'
import { isEmpty, isNotEmpty } from '@/utils/commons'
function SnippetList() {
const [form] = Form.useForm()
const [searchform] = Form.useForm()
const [snippetForm] = Form.useForm()
const editorRef = useRef(null)
const [fetchParamList, ownerList, typeList] =
useSnippetStore(state => [state.fetchParamList, state.ownerList, state.typeList])
const [
fetchParamList,
ownerList,
typeList,
fetchSnippetList,
snippetList,
fetchSnippetDetail,
] = useSnippetStore((state) => [
state.fetchParamList,
state.ownerList,
state.typeList,
state.fetchSnippetList,
state.snippetList,
state.fetchSnippetDetail,
])
const [isSnippetModalOpen, setSnippetModalOpen] = useState(false)
const [editorContent, setEditorContent] = useState(
"<p>Discover the best of the world with one of the <strong>best-rated tour companies for personalized travel</strong>. With over <strong>10,000+ reviews and a 98.8% 5-star rating</strong>, we focus on streamlining your planning and ensuring joyful travels. Whether it's a milestone celebration or a relaxing getaway, let us help create your beautiful journey.</p>",
)
const [editorContent, setEditorContent] = useState('')
const [isHtmlLoading, setHtmlLoading] = useState(false)
const onSnippetFinish = (values) => {
console.log('onSnippetFinish:', values)
// console.info(JSON.stringify(editorRef.current.getEditorState()))
}
@ -39,6 +53,20 @@ function SnippetList() {
// form.resetFields()
}
const handleSearchFinish = (values) => {
console.log('handleSearchFinish:', values)
fetchSnippetList(values)
}
const handleSnippetSelected = (snippetId) => {
setHtmlLoading(true)
fetchSnippetDetail(snippetId)
.then((content) => {
setEditorContent(content)
})
.finally(() => setHtmlLoading(false))
}
useEffect(() => {
fetchParamList()
}, [])
@ -93,10 +121,10 @@ function SnippetList() {
},
]}>
<Select>
<Select.Option value="收款">收款</Select.Option>
<Select.Option value="西藏">西藏</Select.Option>
<Select.Option value="催信">催信</Select.Option>
<Select.Option value="提醒">提醒</Select.Option>
<Select.Option value='收款'>收款</Select.Option>
<Select.Option value='西藏'>西藏</Select.Option>
<Select.Option value='催信'>催信</Select.Option>
<Select.Option value='提醒'>提醒</Select.Option>
</Select>
</Form.Item>
<Form.Item
@ -115,36 +143,28 @@ function SnippetList() {
<Space direction='vertical' size='large' style={{ width: '100%' }}>
<Form
layout={'inline'}
form={form}
form={searchform}
onFinish={handleSearchFinish}
initialValues={{
layout: 'inline',
owner: '', //
type: '',
}}>
<Form.Item label='所有者'>
<Select className='!w-40' options={ownerList} />
<Form.Item label='所有者' name='owner'>
<Select
className='!w-40'
options={ownerList}
showSearch
optionFilterProp='label'
notFoundContent={'找不到'}></Select>
</Form.Item>
<Form.Item label='类别'>
<Select className='!w-40' options={typeList} />
<Form.Item label='类别' name='type'>
<Select className='!w-40' options={typeList} />
</Form.Item>
<Form.Item label='状态'>
<Input placeholder='placeholder' />
</Form.Item>
<Form.Item label='标题'>
<Input placeholder='placeholder' />
<Form.Item label='标题' name='title'>
<Input />
</Form.Item>
<Form.Item>
<Button
type='primary'
onClick={() => {
console.info(editorRef.current)
const editorStateJSONString =
'{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"We are ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"expert in customizing, and best-rated in delivering personalized Asia exploration","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":", ensured by ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"our company-managed local services across Asia","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":". The proof is our over ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"10,000 reviews with 98.8% 5-star ratings","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":" on the most reputable platforms like ","type":"text","version":1},{"detail":0,"format":1,"mode":"normal","style":"","text":"TripAdvisor and Trustpilot","type":"text","version":1},{"detail":0,"format":0,"mode":"normal","style":"","text":".","type":"text","version":1}],"direction":"ltr","format":"start","indent":0,"type":"paragraph","version":1,"textFormat":0,"textStyle":""}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}'
const editorState = editorRef.current.parseEditorState(
editorStateJSONString,
)
editorRef.current.setEditorState(editorState)
}}>
<Button type='primary' htmlType='submit'>
搜索
</Button>
</Form.Item>
@ -153,7 +173,7 @@ function SnippetList() {
onClick={() => {
snippetForm.setFieldsValue({
title: 'Title....',
content: editorContent
content: editorContent,
})
setSnippetModalOpen(true)
}}>
@ -165,27 +185,17 @@ function SnippetList() {
<Col span={8}>
<List
bordered
dataSource={[
'问客人发帖',
'婚礼团upsale',
'泰国相关',
'日本暑期预警',
'Highlights Travel Family Loyalty Club',
]}
dataSource={snippetList}
renderItem={(item) => (
<List.Item
className='hover:bg-stone-50'
onClick={(e) => {
console.info(item)
setEditorContent('<strong>' + item + '</strong>')
onClick={() => {
handleSnippetSelected(item.adi_sn)
}}>
<Row gutter={16} className='w-full'>
<Col span={16}>
<Tag color='magenta'>类型</Tag>
{item}
</Col>
<Col span={8}>
<div className='text-end'>王静</div>
<Col span={20}>{item.adi_title}</Col>
<Col span={4}>
<Tag color='blue'>{item.adi_type_name}</Tag>
</Col>
</Row>
</List.Item>
@ -193,51 +203,7 @@ function SnippetList() {
/>
</Col>
<Col span={16}>
<div className='border-solid border rounded border-gray-300'>
<Space
direction='vertical'
size='middle'
style={{
display: 'flex',
}}>
<pre className='whitespace-pre-wrap break-words ps-6 pe-6'>
<p>
Discover China with the <strong>award-winning</strong> and{' '}
<strong>best-rated</strong> tour company for{' '}
<strong>personalized travel in China</strong>. Honored as{' '}
<strong>China is Leading Tour Operator</strong> by the{' '}
<strong>World Travel Awards</strong>, we boast{' '}
<strong>10,000+ reviews</strong> and a remarkable{' '}
<strong>98.8% 5-star rating</strong>. Our expertise in
customizing personalized China explorations is backed by our
company-managed local services across China. Explore and
kickstart your personalized travel experience with just a
click!
</p>
</pre>
<Flex gap='middle' justify='flex-end' wrap className='p-6'>
<Button
onClick={() => {
setSnippetModalOpen(true)
}}>
编辑
</Button>
<Button
onClick={() => {
//
}}>
复制
</Button>
<Button
danger
onClick={() => {
//
}}>
删除
</Button>
</Flex>
</Space>
</div>
<HtmlPreview value={editorContent} loading={isHtmlLoading} />
</Col>
</Row>
</Space>

Loading…
Cancel
Save