Merge remote-tracking branch 'origin/main'

dev/full-email
Lei OT 5 months ago
commit 1d085285b5

@ -21,7 +21,7 @@ export const EMAIL_HOST = 'https://p9axztuwd7x8a7.mycht.cn/mail-server/service-m
export const API_HOST = 'https://p9axztuwd7x8a7.mycht.cn/whatsapp_server/v2'; export const API_HOST = 'https://p9axztuwd7x8a7.mycht.cn/whatsapp_server/v2';
export const WS_URL = 'wss://p9axztuwd7x8a7.mycht.cn/whatsapp_server'; // prod: export const WS_URL = 'wss://p9axztuwd7x8a7.mycht.cn/whatsapp_server'; // prod:
export const VONAGE_URL = 'https://p9axztuwd7x8a7.mycht.cn/vonage-server'; // 语音和视频接口: export const VONAGE_URL = 'https://p9axztuwd7x8a7.mycht.cn/vonage-server'; // 语音和视频接口:
export const HT3 = process.env.NODE_ENV === 'production' ? 'https://p9axztuwd7x8a7.mycht.cn/ht3' : 'http://127.0.0.1:8000'; export const HT3 = process.env.NODE_ENV === 'production' ? 'https://p9axztuwd7x8a7.mycht.cn/ht3' : 'https://p9axztuwd7x8a7.mycht.cn/ht3';
export const DATE_FORMAT = 'YYYY-MM-DD'; export const DATE_FORMAT = 'YYYY-MM-DD';
export const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss'; export const DATETIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';

@ -3,7 +3,7 @@ import { devtools } from 'zustand/middleware'
import { fetchJSON } from '@/utils/request' import { fetchJSON } from '@/utils/request'
import { isEmpty, isNotEmpty } from '@/utils/commons' import { isEmpty, isNotEmpty } from '@/utils/commons'
import { API_HOST, BUILD_VERSION } from '@/config' import { API_HOST, BUILD_VERSION } from '@/config'
import { usingStorage } from '@/utils/usingStorage'; import { usingStorage } from '@/utils/usingStorage'
export const PERM_MERGE_CONVERSATION = 'merge-conversation' export const PERM_MERGE_CONVERSATION = 'merge-conversation'
export const PERM_ASSIGN_NEW_CONVERSATION = 'assign-new-conversation' export const PERM_ASSIGN_NEW_CONVERSATION = 'assign-new-conversation'
@ -13,133 +13,9 @@ export const PERM_IMPORT_EMAIL = 'import-email'
const WAI_SERVER_KEY = 'G-STR:WAI_SERVER' const WAI_SERVER_KEY = 'G-STR:WAI_SERVER'
const useAuthStore = create(devtools((set, get) => ({ const useAuthStore = create(
loginUser: { devtools(
userId: -1, (set, get) => ({
userIdStr: '-1',
username: '',
avatarUrl: '',
mobile: '',
email: '',
openId: '',
accountList: [],
emailList: [],
whatsAppBusiness: '',
accountName: '',
},
loginStatus: 0,
isPermitted: (perm) => {
const { waiServer } = usingStorage(WAI_SERVER_KEY)
const { loginUser } = get()
if (perm === PERM_USE_WHATSAPP) {
return isNotEmpty(waiServer) // ['370', '143', '495', '404', '383', '227'].includes(loginUser.userId)
}
if (perm === PERM_USE_EMAL) {
return true//['501', '466', '599', '495', '143', '370', '639', '513', '654', '404', '383', '227'].includes(loginUser.userId)
}
// 导入邮件消息,需要配置才能使用
if (perm === PERM_IMPORT_EMAIL && window.localStorage.getItem('PERM_IMPORT_EMAIL')) {
return true
}
if (perm === PERM_MERGE_CONVERSATION) {
return ['404', '383', '227'].includes(loginUser.userId)
}
if (perm === PERM_ASSIGN_NEW_CONVERSATION) {
return ['79', '383', '404', '227'].includes(loginUser.userId)
}
// 以上是 Hardcode 判断
// 动态权限列表参考海外供应商平台实现
},
login: async (authCode) => {
const { setStorage } = usingStorage()
const { saveUserSession, setLoginStatus } = get()
setLoginStatus(200)
const json = await fetchJSON(
'https://p9axztuwd7x8a7.mycht.cn/dingtalk/dingtalkwork/WhatsAppAuth',
{ authCode },
)
if (json.errcode === 0 && isNotEmpty(json.result.opisn)) {
// TODO保存个人 WhatsApp 服务器地址
const waiServer = json.result.whatsappinfo.length > 0 ? json.result.whatsappinfo[0].wai_server : ''
setStorage('G-STR:WAI_SERVER', waiServer)
set(() => ({
loginUser: {
userId: json.result.opisn,
userIdStr: json.result?.accountlist
.map((acc) => {
return acc.OPI_SN
})
.join(','),
emailList: json.result?.emaillist.map(item => {
return {
opi_sn: item.opi_sn,
mat_sn: item.mat_sn,
email: item.email,
default: item.Isdefaultemail == 1,
backup: item.Isbakemail == 1,
}
}),
whatsAppBusiness: json.result.whatsappinfo.length > 0 ? json.result.whatsappinfo[0].whatsapp_waba : '',
whatsAppNo: json.result.whatsappinfo.length > 0 ? json.result.whatsappinfo[0].whatsapp_wa : '',
accountName: json.result.opicode,
username: json.result.nick,
avatarUrl: json.result.avatarUrl,
mobile: '+' + json.result.stateCode + '-' + json.result.mobile,
email: json.result.email,
openId: json.result.openId,
accountList: json.result.accountlist,
},
}))
saveUserSession()
setLoginStatus(302)
} else {
setLoginStatus(403)
}
},
getPrimaryEmail: () => {
const { loginUser } = get()
const defaultList = loginUser.emailList.filter(email => {
return email.default
})
if (defaultList.length > 0) {
return defaultList[0].email
} else {
const backupList = loginUser.emailList.filter(email => {
return email.backup
})
if (backupList.length > 0) {
return backupList[0].email
} else if (loginUser.emailList.length > 0) {
return loginUser.emailList[0].email
}
}
},
setLoginStatus: (code) => {
set(() => ({
loginStatus: code,
}))
},
logout: () => {
window.sessionStorage.clear()
set(() => ({
loginStatus: 0,
loginUser: { loginUser: {
userId: -1, userId: -1,
userIdStr: '-1', userIdStr: '-1',
@ -153,80 +29,203 @@ const useAuthStore = create(devtools((set, get) => ({
whatsAppBusiness: '', whatsAppBusiness: '',
accountName: '', accountName: '',
}, },
}))
}, loginStatus: 0,
loadUserSession: () => { isPermitted: (perm) => {
let sessionData = window.sessionStorage.getItem('GLOBAL_SALES_LOGIN_USER') const { waiServer } = usingStorage(WAI_SERVER_KEY)
// let sessionData ='{"userId":"155","userIdStr":"155","emailList":[],"whatsAppBusiness":"+8617607730395","whatsAppNo":null,"username":"尹诚诚","avatarUrl":"https://static-legacy.dingtalk.com/media/lADPBE1XYG_HAcDNAgDNAgA_512_512.jpg","mobile":"+86-18507832160","email":"ycc@hainatravel.com","openId":"K8BNXMf8ESSr1DzLVUrX7wiEiE","accountList":[{"OPI_SN":155,"OPI_Code":"YCC","OPI_NameCN":"尹诚诚","OPI_DEI_SN":1,"OPI_NameEN":"Yin Chengcheng"}]}' const { loginUser } = get()
// if (window.location.hostname === '202.103.68.93' && window.location.port === '4173' && isEmpty(sessionData)) { if (perm === PERM_USE_WHATSAPP) {
// sessionData = `{"userId":"383","userIdStr":"383,609","emailList":[{"opi_sn":383,"mat_sn":760,"email":"lyj@asiahighlights.com","default":false,"backup":false},{"opi_sn":383,"mat_sn":759,"email":"lyj@chinahighlights.com","default":true,"backup":false},{"opi_sn":383,"mat_sn":758,"email":"lyj@hainatravel.com","default":false,"backup":false}],"username":"廖一军","avatarUrl":"https://static-legacy.dingtalk.com/media/lALPBDDrhXr716HNAoDNAoA_640_640.png","mobile":"+86-18777396951","email":"lyj@hainatravel.com","whatsAppBusiness":"8617458471254","openId":"iioljiPmZ4RPoOYpkFiSn7IKAiEiE","accountList":[{"OPI_SN":383,"OPI_Code":"LYJ","OPI_NameCN":"廖一军","OPI_DEI_SN":7,"OPI_NameEN":"Jimmy Liow"},{"OPI_SN":609,"OPI_Code":"LYJAH","OPI_NameCN":"廖一军ah","OPI_DEI_SN":28,"OPI_NameEN":"Jimmy Liow"}]}` return isNotEmpty(waiServer) // ['370', '143', '495', '404', '383', '227'].includes(loginUser.userId)
}
// window.localStorage.setItem('GLOBAL_SALES_LOGIN_USER', sessionData)
// } if (perm === PERM_USE_EMAL) {
if (import.meta.env.DEV && isEmpty(sessionData)) { return true //['501', '466', '599', '495', '143', '370', '639', '513', '654', '404', '383', '227'].includes(loginUser.userId)
sessionData = window.localStorage.getItem('GLOBAL_SALES_LOGIN_USER') }
}
// 导入邮件消息,需要配置才能使用
if (sessionData !== null) { if (perm === PERM_IMPORT_EMAIL && window.localStorage.getItem('PERM_IMPORT_EMAIL')) {
const sesstionObj = JSON.parse(sessionData) return true
set(() => ({ }
loginUser: sesstionObj,
})) if (perm === PERM_MERGE_CONVERSATION) {
} return ['404', '383', '227'].includes(loginUser.userId)
}, }
saveUserSession: () => { if (perm === PERM_ASSIGN_NEW_CONVERSATION) {
const { loginUser } = get() return ['79', '383', '404', '227'].includes(loginUser.userId)
window.sessionStorage.setItem( }
'GLOBAL_SALES_LOGIN_USER', // 以上是 Hardcode 判断
JSON.stringify(loginUser), // 动态权限列表参考海外供应商平台实现
) },
},
login: async (authCode) => {
setWhatsAppProfile: async (userId, whatsAppBusiness, whatsAppNo) => { const { setStorage } = usingStorage()
const { loginUser, saveUserSession } = get() const { saveUserSession, setLoginStatus } = get()
const postWABAUrl = `${API_HOST}/v2/set_whatsapp_info`
setLoginStatus(200)
const params = {opi_sn: userId, whatsapp_waba: whatsAppBusiness, whatsapp_wa: whatsAppNo.replace(/\D/g, '')};
const json = await fetchJSON('https://p9axztuwd7x8a7.mycht.cn/dingtalk/dingtalkwork/WhatsAppAuth', { authCode })
return fetchJSON(postWABAUrl, params)
.then(json => { if (json.errcode === 0 && isNotEmpty(json.result.opisn)) {
if (json.errcode === 0) { // TODO保存个人 WhatsApp 服务器地址
const waiServer = json.result.whatsappinfo.length > 0 ? json.result.whatsappinfo[0].wai_server : ''
setStorage('G-STR:WAI_SERVER', waiServer)
set(() => ({ set(() => ({
loginUser: { loginUser: {
...loginUser, userId: json.result.opisn,
whatsAppNo: whatsAppNo, userIdStr: json.result?.accountlist
whatsAppBusiness: whatsAppBusiness, .map((acc) => {
} return acc.OPI_SN
})
.join(','),
emailList: json.result?.emaillist.map((item) => {
return {
opi_sn: item.opi_sn,
mat_sn: item.mat_sn,
email: item.email,
default: item.Isdefaultemail == 1,
backup: item.Isbakemail == 1,
}
}),
whatsAppBusiness: json.result.whatsappinfo.length > 0 ? json.result.whatsappinfo[0].whatsapp_waba : '',
whatsAppNo: json.result.whatsappinfo.length > 0 ? json.result.whatsappinfo[0].whatsapp_wa : '',
accountName: json.result.opicode,
username: json.result.nick,
avatarUrl: json.result.avatarUrl,
mobile: '+' + json.result.stateCode + '-' + json.result.mobile,
email: json.result.email,
openId: json.result.openId,
accountList: json.result.accountlist,
},
})) }))
saveUserSession() saveUserSession()
setLoginStatus(302)
} else { } else {
throw new Error(json?.errmsg + ': ' + json.errcode) setLoginStatus(403)
} }
}) },
},
getPrimaryEmail: () => {
sendNotify: async () => { const { loginUser } = get()
const { loginUser } = get()
const notifyUrl = 'https://p9axztuwd7x8a7.mycht.cn/dingtalk/dingtalkwork/SendMDMsgByDingRobotToGroup' const defaultList = loginUser.emailList.filter((email) => {
return email.default
const params = { })
groupid: 'cidFtzcIzNwNoiaGU9Q795CIg==',
msgTitle: '有人求助', if (defaultList.length > 0) {
msgText: loginUser.username + '上传了销售平台' + BUILD_VERSION + '的日志' return defaultList[0].email
};
return fetchJSON(notifyUrl, params)
.then(json => {
if (json.errcode === 0) {
console.info('发送通知成功')
} else { } else {
throw new Error(json?.errmsg + ': ' + json.errcode) const backupList = loginUser.emailList.filter((email) => {
return email.backup
})
if (backupList.length > 0) {
return backupList[0].email
} else if (loginUser.emailList.length > 0) {
return loginUser.emailList[0].email
}
} }
}) },
},
}), { name: 'authStore' })) setLoginStatus: (code) => {
set(() => ({
loginStatus: code,
}))
},
logout: () => {
window.sessionStorage.clear()
set(() => ({
loginStatus: 0,
loginUser: {
userId: -1,
userIdStr: '-1',
username: '',
avatarUrl: '',
mobile: '',
email: '',
openId: '',
accountList: [],
emailList: [],
whatsAppBusiness: '',
accountName: '',
},
}))
},
loadUserSession: () => {
let sessionData =
import.meta.env.PROD === 'production'
? window.sessionStorage.getItem('GLOBAL_SALES_LOGIN_USER')
: '{"userId":"155","userIdStr":"155","emailList":[],"whatsAppBusiness":"+8617607730395","whatsAppNo":null,"username":"尹诚诚","avatarUrl":"https://static-legacy.dingtalk.com/media/lADPBE1XYG_HAcDNAgDNAgA_512_512.jpg","mobile":"+86-18507832160","email":"ycc@hainatravel.com","openId":"K8BNXMf8ESSr1DzLVUrX7wiEiE","accountList":[{"OPI_SN":155,"OPI_Code":"YCC","OPI_NameCN":"尹诚诚","OPI_DEI_SN":1,"OPI_NameEN":"Yin Chengcheng"}]}'
// if (window.location.hostname === '202.103.68.93' && window.location.port === '4173' && isEmpty(sessionData)) {
// sessionData = `{"userId":"383","userIdStr":"383,609","emailList":[{"opi_sn":383,"mat_sn":760,"email":"lyj@asiahighlights.com","default":false,"backup":false},{"opi_sn":383,"mat_sn":759,"email":"lyj@chinahighlights.com","default":true,"backup":false},{"opi_sn":383,"mat_sn":758,"email":"lyj@hainatravel.com","default":false,"backup":false}],"username":"廖一军","avatarUrl":"https://static-legacy.dingtalk.com/media/lALPBDDrhXr716HNAoDNAoA_640_640.png","mobile":"+86-18777396951","email":"lyj@hainatravel.com","whatsAppBusiness":"8617458471254","openId":"iioljiPmZ4RPoOYpkFiSn7IKAiEiE","accountList":[{"OPI_SN":383,"OPI_Code":"LYJ","OPI_NameCN":"廖一军","OPI_DEI_SN":7,"OPI_NameEN":"Jimmy Liow"},{"OPI_SN":609,"OPI_Code":"LYJAH","OPI_NameCN":"廖一军ah","OPI_DEI_SN":28,"OPI_NameEN":"Jimmy Liow"}]}`
// window.localStorage.setItem('GLOBAL_SALES_LOGIN_USER', sessionData)
// }
if (import.meta.env.DEV && isEmpty(sessionData)) {
sessionData = window.localStorage.getItem('GLOBAL_SALES_LOGIN_USER')
}
if (sessionData !== null) {
const sesstionObj = JSON.parse(sessionData)
set(() => ({
loginUser: sesstionObj,
}))
}
},
saveUserSession: () => {
const { loginUser } = get()
window.sessionStorage.setItem('GLOBAL_SALES_LOGIN_USER', JSON.stringify(loginUser))
},
setWhatsAppProfile: async (userId, whatsAppBusiness, whatsAppNo) => {
const { loginUser, saveUserSession } = get()
const postWABAUrl = `${API_HOST}/v2/set_whatsapp_info`
const params = { opi_sn: userId, whatsapp_waba: whatsAppBusiness, whatsapp_wa: whatsAppNo.replace(/\D/g, '') }
return fetchJSON(postWABAUrl, params).then((json) => {
if (json.errcode === 0) {
set(() => ({
loginUser: {
...loginUser,
whatsAppNo: whatsAppNo,
whatsAppBusiness: whatsAppBusiness,
},
}))
saveUserSession()
} else {
throw new Error(json?.errmsg + ': ' + json.errcode)
}
})
},
sendNotify: async () => {
const { loginUser } = get()
const notifyUrl = 'https://p9axztuwd7x8a7.mycht.cn/dingtalk/dingtalkwork/SendMDMsgByDingRobotToGroup'
const params = {
groupid: 'cidFtzcIzNwNoiaGU9Q795CIg==',
msgTitle: '有人求助',
msgText: loginUser.username + '上传了销售平台' + BUILD_VERSION + '的日志',
}
return fetchJSON(notifyUrl, params).then((json) => {
if (json.errcode === 0) {
console.info('发送通知成功')
} else {
throw new Error(json?.errmsg + ': ' + json.errcode)
}
})
},
}),
{ name: 'authStore' },
),
)
export default useAuthStore export default useAuthStore

@ -1,7 +1,7 @@
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { Form, Input, Button, DatePicker, Select, Table } from 'antd' import { Form, Input, Button, DatePicker, Select, Table } from 'antd'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { ReadIcon, DeliverIcon, SentIcon ,WaitingIcon,FailedIcon} from '@/components/Icons' import { ReadIcon, DeliverIcon, SentIcon, WaitingIcon, FailedIcon } from '@/components/Icons'
import useCustomerRelationStore from '@/stores/CustomerRelationStore' import useCustomerRelationStore from '@/stores/CustomerRelationStore'
const { RangePicker } = DatePicker const { RangePicker } = DatePicker
@ -14,7 +14,7 @@ const statusIconMap = {
sent: <SentIcon title='sent' />, sent: <SentIcon title='sent' />,
failed: <FailedIcon title='failed' />, failed: <FailedIcon title='failed' />,
accepted: <WaitingIcon title='accepted' />, accepted: <WaitingIcon title='accepted' />,
default: <WaitingIcon title='waiting' /> default: <WaitingIcon title='waiting' />,
} }
const Index = () => { const Index = () => {
@ -37,6 +37,71 @@ const Index = () => {
fetchSearchTasks(formattedValues) fetchSearchTasks(formattedValues)
} }
// crt_template msg_status
const templateStatusCount = {}
tasksList.forEach((item) => {
const { crt_template, msg_status } = item
if (msg_status !== null && msg_status !== undefined) {
if (!templateStatusCount[crt_template]) {
templateStatusCount[crt_template] = {}
}
if (!templateStatusCount[crt_template][msg_status]) {
templateStatusCount[crt_template][msg_status] = 0
}
templateStatusCount[crt_template][msg_status]++
}
})
//
const groupedResult = {}
for (const template in templateStatusCount) {
const total = Object.values(templateStatusCount[template]).reduce((acc, val) => acc + val, 0)
groupedResult[template] = {}
for (const status in templateStatusCount[template]) {
const count = templateStatusCount[template][status]
const percentage = ((count / total) * 100).toFixed(2)
groupedResult[template][`${status}_count`] = count
groupedResult[template][`${status}_percentage`] = `${percentage}%`
}
}
// groupedResult
const groupedData = Object.entries(groupedResult).map(([template, stats]) => {
return {
key: template,
crt_template: template,
...stats,
}
})
//
const groupedColumns = []
groupedColumns.push({
title: '模板名称',
dataIndex: 'crt_template',
key: 'crt_template',
})
const allStatuses = new Set()
tasksList.forEach((item) => {
if (item.msg_status !== null && item.msg_status !== undefined) {
allStatuses.add(item.msg_status)
}
})
allStatuses.forEach((status) => {
groupedColumns.push({
title: `${status} 计数`,
dataIndex: `${status}_count`,
key: `${status}_count`,
})
groupedColumns.push({
title: `${status} 百分比`,
dataIndex: `${status}_percentage`,
key: `${status}_percentage`,
})
})
const DATE_RANGE_PRESETS = [ const DATE_RANGE_PRESETS = [
{ {
label: '本周', label: '本周',
@ -127,11 +192,11 @@ const Index = () => {
</Form.Item> </Form.Item>
</Form> </Form>
{/* 搜索结果 */}
<span>搜索结果总数: {tasksList && tasksList.length}</span> <span>搜索结果总数: {tasksList && tasksList.length}</span>
<Table dataSource={tasksList} columns={columns} pagination={false} rowKey='crt_sn' loading={loading} /> <Table dataSource={tasksList} columns={columns} pagination={false} rowKey='crt_sn' loading={loading} />
<h2>统计结果</h2>
<Table dataSource={groupedData} columns={groupedColumns} pagination={false} loading={loading} />
</> </>
) )
} }

Loading…
Cancel
Save