feat: 使用window.getSelection().addRange(range) 方式复制 HTML;测试设置商业号身份

2.0/email-builder
Jimmy Liow 8 months ago committed by Lei OT
parent 52b62f5b1f
commit 7a0bcf8f81

@ -1,6 +1,6 @@
# Global sales
销售平台 2.0
销售平台通过邮件、WhatsApp Business Account、WhatsApp 和客人沟通。
## 开发设置
@ -10,8 +10,15 @@
2. 运行开发环境dev.bat
3. 打包代码build.bat
## 版本设置
遵循 [Semantic Versioning 2.0.0](http://semver.org/lang/zh-CN/) 语义化版本规范。
修订版本号:日常 bugfix 更新。(如果有紧急的 bugfix则任何时候都可发布
次版本号:有新特性的向下兼容的版本。
主版本号:含有破坏性更新和新特性。
npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]
npm version premajor --no-git-tag-version

@ -1,6 +1,7 @@
import { create } from 'zustand'
import { fetchJSON } from '@/utils/request'
import { fetchJSON, postForm } from '@/utils/request'
import { isEmpty, isNotEmpty } from '@/utils/commons'
import { API_HOST } from '@/config'
export const PERM_MERGE_CONVERSATION = 'merge-conversation'
export const PERM_ASSIGN_NEW_CONVERSATION = 'assign-new-conversation'
@ -142,6 +143,21 @@ const useAuthStore = create((set, get) => ({
navigator.clipboard.writeText(sessionData)
}
},
setWhatsAppBusiness: async (userId, whatsAppBusiness) => {
const postWABAUrl = `${API_HOST}/v2/set_whatsapp_info`
const params = {opi_sn: userId, whatsapp_waba: whatsAppBusiness};
return fetchJSON(postWABAUrl, params)
.then(json => {
if (json.errcode === 0) {
console.info(json)
} else {
throw new Error(json?.errmsg + ': ' + json.errcode)
}
})
},
}))
export default useAuthStore

@ -3,7 +3,7 @@ import { Conditional } from '@/components/Conditional'
import { isNotEmpty } from '@/utils/commons'
const HtmlPreview = (props) => {
const { loading = false, value, onEdit, onCopy, onDelete } = props
const { loading = false, value, onEdit, onCopied, onDelete } = props
if (loading) {
return <Skeleton className='p-6' active />
@ -14,7 +14,7 @@ const HtmlPreview = (props) => {
<Conditional
condition={isNotEmpty(value)}
whenTrue={
<pre className='whitespace-pre-wrap break-words ps-6 pe-6' dangerouslySetInnerHTML={{__html:value}}>
<pre id='__preHtml__' className='whitespace-pre-wrap break-words ps-6 pe-6' dangerouslySetInnerHTML={{__html: value}}>
</pre>
}
whenFalse={<Empty className='p-6' description={false} />}
@ -27,7 +27,13 @@ const HtmlPreview = (props) => {
</Button>
<Button
onClick={() => {
navigator.clipboard.writeText(value)
const range = document.createRange()
range.selectNode(document.getElementById('__preHtml__'))
window.getSelection().removeAllRanges()
window.getSelection().addRange(range)
document.execCommand('copy')
// window.getSelection().removeAllRanges()
onCopied()
}}>
复制
</Button>

@ -1,33 +1,10 @@
import { useEffect } from 'react'
import {
Row,
Col,
Space,
Descriptions,
Avatar,
Tag,
Divider,
List,
Alert,
Button,
Flex,
Select,
Spin,
Form,
Typography,
QRCode,
} from 'antd'
import {
UserOutlined,
InfoCircleOutlined,
CloseCircleFilled,
ReloadOutlined,
CheckCircleFilled,
} from '@ant-design/icons'
import { Row, Col, Space, Descriptions, Avatar, Tag, Divider, List, Alert, Button, Flex, Select, Spin, Form, Typography, QRCode, Tooltip } from 'antd'
import { UserOutlined, InfoCircleOutlined, CloseCircleFilled, ReloadOutlined, CheckCircleFilled } from '@ant-design/icons'
import useAuthStore from '@/stores/AuthStore'
function Profile() {
const loginUser = useAuthStore((state) => state.loginUser)
const [loginUser, setWhatsAppBusiness] = useAuthStore((state) => [state.loginUser, state.setWhatsAppBusiness])
useEffect(() => {
console.info(loginUser)
@ -41,12 +18,12 @@ function Profile() {
case 'expired':
return (
<div>
<CloseCircleFilled
<CheckCircleFilled
style={{
color: 'red',
color: '#52c41a',
}}
/>{' '}
{info.locale?.expired}
8618754124786 已登录
<p>
<Button type='link' onClick={info.onRefresh}>
<ReloadOutlined /> {info.locale?.refresh}
@ -84,35 +61,34 @@ function Profile() {
<Descriptions title='个人资料' layout='vertical' column={1}>
<Descriptions.Item label='名字'>
<Space size='middle'>
<Avatar src={loginUser.avatarUrl}>
{loginUser.username.substring(1)}
</Avatar>
<Avatar src={loginUser.avatarUrl}>{loginUser.username.substring(1)}</Avatar>
{loginUser.username}
</Space>
</Descriptions.Item>
<Descriptions.Item label='HT 账号'>
{loginUser.accountList?.map((a) => {
return (
<Tag
key={a.OPI_Code}
icon={<UserOutlined />}
bordered={false}>
<Tag key={a.OPI_Code} icon={<UserOutlined />} bordered={false}>
{a.OPI_Code}
</Tag>
)
})}
</Descriptions.Item>
<Descriptions.Item label='商业号身份'>
<Descriptions.Item
label={
<Space>
<Tooltip title='你所属的业务部门'>
<InfoCircleOutlined />
</Tooltip>
<span>商业号身份</span>
</Space>
}>
<Form
layout='vertical'
// form={form}
>
<Form.Item
tooltip={{
title: '你所属的业务部门',
icon: <InfoCircleOutlined />,
}}>
<Form.Item>
<Select
defaultValue='8617607730395'
options={[
@ -147,7 +123,13 @@ function Profile() {
/>
</Form.Item>
<Form.Item>
<Button type='primary'>保存</Button>
<Button
type='primary'
onClick={() => {
setWhatsAppBusiness(383, 8617607730395)
}}>
保存
</Button>
</Form.Item>
</Form>
</Descriptions.Item>
@ -158,9 +140,7 @@ function Profile() {
header={<div>邮箱</div>}
dataSource={loginUser.emailList}
renderItem={(item) => {
const isDefault = item.default ? (
<Tag color='green'>默认</Tag>
) : null
const isDefault = item.default ? <Tag color='green'>默认</Tag> : null
const isBackup = item.backup ? <Tag color='cyan'>备用</Tag> : null
return (
<List.Item>
@ -180,22 +160,15 @@ function Profile() {
<Typography.Paragraph>
<ul>
<li>在手机上打开 WhatsApp</li>
<li>点击已关联的设备然后点击关联新设备</li>
<li>将手机对准屏幕扫描二维码</li>
<li>点击已关联的设备点击关联新设备</li>
<li>将手机对准屏幕扫描二维码</li>
</ul>
</Typography.Paragraph>
</Typography>
</Col>
<Col span={6}>
<Flex gap='middle' vertical justify={'center'} align={'center'}>
<QRCode
size={264}
value={'https://web.whatsapp.com/'}
status='scanned'
statusRender={customStatusRender}
/>
<Alert message='WhatsApp8618754124786' type='success' showIcon />
<Button type='primary'>退出</Button>
<QRCode size={264} value={'https://web.whatsapp.com/'} status='expired' statusRender={customStatusRender} />
</Flex>
</Col>
</Row>

@ -11,15 +11,19 @@ import {
Modal,
Select,
Divider,
Empty,
message,
} from 'antd'
import { useState, useRef, useEffect } from 'react'
import LexicalEditorInput from './LexicalEditorInput'
import HtmlPreview from './HtmlPreview'
import useSnippetStore from '@/stores/SnippetStore'
import LexicalEditor from '@/components/LexicalEditor'
import { isEmpty, isNotEmpty } from '@/utils/commons'
function SnippetList() {
const [messageApi, contextHolder] = message.useMessage()
const [searchform] = Form.useForm()
const [snippetForm] = Form.useForm()
@ -203,11 +207,12 @@ function SnippetList() {
<Col span={16}>
<HtmlPreview value={editorContent} loading={isHtmlLoading}
onEdit={() => console.info('onEdit')}
onCopy={() => console.info('onCopy')}
onCopied={() => messageApi.success('已复制')}
onDelete={() => console.info('onDelete')} />
</Col>
</Row>
</Space>
{contextHolder}
</>
)
}

Loading…
Cancel
Save