Compare commits

..

1 Commits

Author SHA1 Message Date
Lei OT 8540184376 manualChunk 1 year ago

@ -7,7 +7,7 @@ module.exports = {
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['node_modules/*', 'dist', '.eslintrc.cjs'],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],

15
.gitignore vendored

@ -11,11 +11,6 @@ node_modules
dist
dist-ssr
*.local
distTest
dev-dist
tmp
schema*
.gitkeep
# Editor directories and files
.vscode/*
@ -29,13 +24,3 @@ schema*
*.sw?
/package-lock.json
**/LexicalEditor0
*.zip
.env.*
vonage-client*
**/test
*.bak

@ -1,18 +0,0 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 200,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"quoteProps": "as-needed",
"jsxSingleQuote": true,
"bracketSpacing": true,
"jsxBracketSameLine": true,
"singleAttributePerLine": false,
"arrowParens": "always",
"requirePragma": false,
"insertPragma": false,
"proseWrap": "preserve",
"htmlWhitespaceSensitivity": "ignore"
}

@ -1,46 +1,14 @@
# Global sales
销售平台通过邮件、WhatsApp Business Account、WhatsApp 和客人沟通。
聊天式销售平台
## 开发设置
所有命令都在 cmd 目录,
1. 安装组件npm install
2. 运行开发环境dev.bat
3. 打包代码build.bat
## 版本设置
遵循 [Semantic Versioning 2.0.0](http://semver.org/lang/zh-CN/) 语义化版本规范。
修订版本号:日常 bugfix 更新。(如果有紧急的 bugfix则任何时候都可发布
次版本号:有新特性的向下兼容的版本。
主版本号:含有破坏性更新和新特性。
2. 运行开发环境npm run dev 或者 start.bat
3. 打包代码npm run build 或者 build.bat
npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]
npm version preminor --preid alpha --no-git-tag-version
npm version preminor --preid beta --no-git-tag-version
1.2.0 -> 1.3.0-beta.0
npm version premajor --no-git-tag-version
1.0.0 -> 2.0.0-0
npm version prerelease --no-git-tag-version
2.0.0-0 -> 2.0.0-1 -> 2.0.0-2 ..n -> 2.0.0-n
npm version patch --no-git-tag-version
2.0.0-n -> 2.0.0
## 相关文档
[聊天式销售平台需求文档](https://www.kdocs.cn/l/calaUjgmCmDA?from=docs&reqtype=kdocs&startTime=1703645330177&createDirect=true&newFile=true)
## vonage语音视频
安装模块 npm i @vonage/client-sdk
## 本机测试账号
GLOBAL_SALES_LOGIN_USER
{"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":false,"backup":false},{"opi_sn":383,"mat_sn":758,"email":"lyj@hainatravel.com","default":false,"backup":false},{"opi_sn":383,"mat_sn":761,"email":"lyj@chinahighlights.net","default":true,"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"}]}

@ -1 +0,0 @@
npm run build

@ -1 +0,0 @@
npm run dev

@ -1 +0,0 @@
npm version patch

@ -1 +0,0 @@
npm version prerelease

@ -1,83 +0,0 @@
## 发送template 消息
### 模板原文
```json
{
"wabaId": "190290134156880",
"name": "order_updated_specialist_assigned_sharon",
"language": "en",
"messageSendTtlSeconds": -1,
"components": [
{
"type": "BODY",
"text": "Hi {{customer_name}}, this is {{your_name1}} your trip advisor. \nHow are you? {{free_style}} \nKindest regards, {{your_name2}}. ",
"example": {
"body_text": [
[
"Mike",
"Coco",
"I'm following up on your itinerary",
"Coco2"
]
]
}
}
],
"category": "UTILITY",
"status": "APPROVED",
"qualityRating": "UNKNOWN",
"reason": "NONE",
"createTime": "2024-12-11T08:31:11.290Z",
"updateTime": "2024-12-11T08:31:34.610Z",
"statusUpdateEvent": "APPROVED"
}
```
### 发送模板消息, 数据结构
```json
{
"action": "message", // 固定值
"actionId": "190.3c8322de-68df-4f9e-be8e-d92e7a13b7d7", // .uuid()
"renderId": "190.3c8322de-68df-4f9e-be8e-d92e7a13b7d7", // 忽略
"externalId": 190, // 留空
"to": "8613557032060",
"from": "+8617607730395",
"msgtype": "template", // 固定值
"msgcontent": {
"name": "order_updated_specialist_assigned_sharon", // 模板名称. 从原文
"language": {
"code": "en" // 语言. 从原文
},
"components": [ // 没有参数的组件, 建议不传. 组件顺序也会报错
{
"type": "body",
"parameters": [ // 模板参数. 按 当前 `type` 中的参数顺序排列
{
"type": "text",
"text": "test OT 22" // 参数值: 不能换行, 连续空格<4
},
{
"type": "text",
"text": "yoyo"
},
{
"type": "text",
"text": "111"
},
{
"type": "text",
"text": "yoyo"
}
],
"text": "Hi test OT 22, this is yoyo your trip advisor. \nHow are you? 111 \nKindest regards, yoyo. " // 拼接一个完整内容
}
]
},
"opi_sn": "404", // 发送人 ID
"coli_sn": 1082591,
"conversationid": 190 // 忽略
}
```

Binary file not shown.

@ -1,17 +1,9 @@
## 查找出掉线的 WhatsApp
select *
from whatsapp_individual.connections
where status IN ('offline')
and wa_id not in ('8618777396951', '8613557032060','8613317835586')
and wa_id <> 'null'
//
SELECT group_concat(opi_sn separator ',') as 'sn_list' FROM (
SELECT
opi_sn,COUNT(*)
FROM whatsapp_session
where opi_sn is not null and opi_sn not in (29,383,404,227)
AND (last_send_time >= '2024-4-15' AND last_send_time <= '2024-4-21')
GROUP by opi_sn
) session_count
@ -23,160 +15,16 @@ FROM
DeleteFlag = 0 and
OPI_SN in (162,31,32,33,34,599,600,353,352,350,351,35,606,495,293,525,114,587,585,519,522,476,354,451,216,143,586,539,370,512)
// HT
SELECT opi.OPI_Code,
opi.OPI_Name, tpa.* FROM dbo.ThirdPlatformAccount_Bind tpa
left join OperatorInfo opi
on opi.opi_sn = tpa.TPA_OPI_SN
where opi.DeleteFlag = 0
//
SELECT *
FROM whatsapp_session
WHERE coli_sn = 0 AND last_received_time IS NOT NULL ## AND opi_sn = 599
ORDER BY last_received_time DESC
//
// WA
SELECT *
FROM whatsapp_session
WHERE whatsapp_phone_number_bak IS not NULL
/**
* ---------------------------------------------------------
*
*/
-- title: query order info
SELECT cli.COLI_ID,cli.COLI_SN
,cli.COLI_GRI_SN
,mi.MEI_SN
-- ,cl.CUL_SN
,oi.OPI2_Name AS
,'#-------#'
,cli.COLI_OrderStartDate
,(mi.MEI_FirstName + ' | '+ mi.MEI_LastName) AS member_name
,cli.*
,'#-------#',cl.*
,'#-------#', mi.*
FROM ConfirmLineInfo AS cli
LEFT JOIN CUstomerList AS cl ON cli.COLI_SN = cl.CUL_COLI_SN
LEFT JOIN MEmberInfo AS mi ON mi.MEI_SN = cl.CUL_CUI_SN
LEFT JOIN OperatorInfo2 AS oi ON oi.opi2_opi_sn = cli.COLI_OPI_ID AND oi.OPI2_LGC =2
WHERE 1 = 1
-- AND mi.MEI_FirstName = 'CHEN WANG'
AND COLI_ID = 'Lib231120146'
-- AND CUL_COLI_SN = 1086888
--
;
UPDATE whatsapp_session
SET coli_sn = 1075451
WHERE sn = 57 AND whatsapp_phone_number = '14048496022';
UPDATE whatsapp_inboundmessage msg
INNER JOIN whatsapp_session s ON s.whatsapp_phone_number = msg.froms
AND msg.msg_direction = 'inbound'
SET msg.coli_sn = s.coli_sn
WHERE ifnull(msg.coli_sn, 0) = 0
AND msg.msg_direction = 'inbound'
AND msg.froms = '393343998897';
UPDATE whatsapp_inboundmessage msg
INNER JOIN whatsapp_session s ON s.whatsapp_phone_number = msg.tos
AND msg.msg_direction = 'outbound'
SET msg.coli_sn = s.coli_sn
WHERE ifnull(msg.coli_sn, 0) = 0
AND msg.msg_direction = 'outbound'
AND msg.tos = '393343998897';
/**
* end
* ---------------------------------------------------------
*/
/**
* ---------------------------------------------------------
*
*/
INSERT INTO sale_system.whatsapp_session (
whatsapp_phone_number,whatsapp_name, opi_sn,coli_sn,session_enable)
VALUES ('6282145142470','',162,0,1);
/**
* end
* ---------------------------------------------------------
*/
/**
* ---------------------------------------------------------
*
* , WhatsApp
* 1. coli_sn, coli_id, whatsapp_name
* 2. : tos, coli_sn
*/
UPDATE sale_system.whatsapp_session
SET whatsapp_name='Luiz Ribeiro', coli_sn=1092511, coli_id='L240509014'
WHERE whatsapp_phone_number='553499923993' AND opi_sn = 587;
UPDATE sale_system.whatsapp_inboundmessage
SET tos='553499923993', coli_sn=1092511
WHERE tos = '5534999923993' AND opi_sn = 587;
/**
* end
* ---------------------------------------------------------
*/
/**
WhatsApp
*/
WHERE opi_sn IS null
select * from whatsapp_user
##where wau_opi_sn in (252, 261,264,265,330,360,376,413,421,453,605,620) ## 国际部
where wau_opi_sn in (495, 143, 370, 114, 513, 514, 517, 522, 550, 587,354, 414, 599, 606, 639, 648, 654, 662, 674, 676,391, 451, 476, 501, 512, 525, 528, 585, 586, 644) ## GH
-- 查找每个服务器在线的 WA 数量
select connect_name, count(*)
from whatsapp_individual.connections
where status IN ('open')
group by connect_name
set SESSION group_concat_max_len=4294967295;
-- 查找已经配置 WAI 服务的顾问
select group_concat(wau_whatsapp separator ''',''') as 'sn_list'
from sale_system.whatsapp_user
where wau_wai_server is not null
## 查找在线的 WhatsApp
SELECT group_concat(sesson_id separator ''',''') as 'sesson_list'
FROM whatsapp_individual.connections
where status = 'open'
-- 查找掉线的顾问
select group_concat(sesson_id separator ''',''') as 'sesson_list' from whatsapp_individual.connections
where status IN ('offline')
and wa_id not in ('8618777396951', '8613557032060','8613317835586')
## 查找 GH 没有扫码登录的顾问
select group_concat(wau_opi_sn separator ',') as 'sn_list'
from whatsapp_user
where wau_whatsapp not in ('8613317835586','8617607732272','8613978392676','8618378304803','8617607730629','8619107833371','8619107835971','8617607731491','8615080129281','8617607737720','8618777396951','8618078444860','8615778462307','8617774702925','8615078398450','8619178340224','8617607731153','8617607735120','8617607737646','8618877388203','8615778493040','8613617733956','8618290167273','8617776515283','8617607736381','8613557032060','8613667839691','8618378388403','8613635132972','8617607734598','8617607732512','8615878340720')
and wau_opi_sn in (495, 143, 370, 114, 513, 514, 517, 522, 550, 587,354, 414, 599, 606, 639, 648, 654, 662, 674, 676,391, 451, 476, 501, 512, 525, 528, 585, 586, 644)
-- 查找使用 WhatsApp 顾问信息
SELECT
OPI_SN, OPI_Code,OPI_Name,OPI_DEI_SN,OPI_FirstName,OPI_RealName, DeleteFlag
FROM
dbo.OperatorInfo WHERE
OPI_SN in (143,476,528,391)
--OPI_SN in (495, 143, 370, 114, 513, 514, 517, 522, 550, 587)
SELECT OPI_RealName + '(' + CAST(OPI_SN AS VARCHAR(100)) + ')',OPI_SN
FROM
dbo.OperatorInfo
where
--DeleteFlag = 0 and
OPI_SN in (79,85,114,119,135,143,155,162,178,210,216,222,225,252,261,264,265,273,293,296,311,330,343,347,348,354,360,370,376,387,391,412,413,414,421,441,444,451,453,456,466,468,476,495,497,501,509,512,513,514,517,519,522,525,527,528,539,550,573,585,586,587,592,599,600,605,606,611,617,620,639,644,648,654,656,659,662,663,674,676,690,691)
and OPI_RealName in ('兰芬','孙俊垚','王继伟','曾君','潘宏宇','郑美珍','张丽娟','张倩倩','赵泽菲','王影','陆力影','吕燕珍','何秋云','沈慧香')

File diff suppressed because it is too large Load Diff

@ -5,12 +5,10 @@
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>销售平台</title>
<link rel="preconnect" crossorigin="anonymous" href="https://haina-sale-system.oss-cn-shenzhen.aliyuncs.com">
<link rel="preconnect" crossorigin="anonymous" href="https://hiana-crm.oss-ap-southeast-1.aliyuncs.com">
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
<p style="display: none;">VERSION: %BUILD_VERSION%</p>
<p style="display: none;">BUILD_DATE: %BUILD_DATE%</p>
</body>
</html>

@ -1,18 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<title>Sales CRM Maintenance</title>
</head>
<body>
<div id="maintenance-root"></div>
<script type="module" src="/src/maintenance.jsx"></script>
</body>
</html>

@ -1,7 +1,7 @@
{
"name": "global-sales",
"private": true,
"version": "1.5.0-1",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
@ -10,37 +10,32 @@
"preview": "vite preview"
},
"dependencies": {
"@dckj/react-better-modal": "^0.1.2",
"@lexical/react": "^0.20.0",
"@vonage/client-sdk": "^2.0.0",
"antd": "^5.25.2",
"dayjs": "^1.11.13",
"dingtalk-jsapi": "^3.0.41",
"emoji-picker-react": "^4.12.0",
"lexical": "^0.20.0",
"react": "^18.3.1",
"react-chat-elements": "^12.0.17",
"react-dom": "^18.3.1",
"react-router-dom": "^6.30.1",
"antd": "^5.14.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.10",
"emoji-picker-react": "^4.8.0",
"react": "^18.2.0",
"react-chat-elements": "^12.0.11",
"react-dom": "^18.2.0",
"react-router-dom": "^6.21.1",
"rxjs": "^7.8.1",
"uuid": "^9.0.1",
"zustand": "^4.5.7"
"vite-plugin-pwa": "^0.19.6",
"zustand": "^4.5.0"
},
"devDependencies": {
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.17",
"eslint": "^8.45.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.14",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.15",
"eslint-plugin-react-refresh": "^0.4.3",
"postcss": "^8.4.33",
"tailwindcss": "^3.4.1",
"vite": "^4.5.1",
"vite-plugin-css-modules": "^0.0.1",
"vite-plugin-pwa": "^0.21.0",
"vite-plugin-svgr": "^4.3.0",
"vite-plugin-windicss": "^1.9.3",
"windicss": "^3.5.6"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1721878224733" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5115" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M926.47619 355.644952V780.190476a73.142857 73.142857 0 0 1-73.142857 73.142857H170.666667a73.142857 73.142857 0 0 1-73.142857-73.142857V355.644952l304.103619 257.828572a170.666667 170.666667 0 0 0 220.745142 0L926.47619 355.644952zM853.333333 170.666667a74.044952 74.044952 0 0 1 26.087619 4.778666 72.704 72.704 0 0 1 30.622477 22.186667 73.508571 73.508571 0 0 1 10.678857 17.67619c3.169524 7.509333 5.12 15.652571 5.607619 24.210286L926.47619 243.809524v24.380952L559.469714 581.241905a73.142857 73.142857 0 0 1-91.306666 2.901333l-3.632762-2.925714L97.52381 268.190476v-24.380952a72.899048 72.899048 0 0 1 40.155428-65.292191A72.97219 72.97219 0 0 1 170.666667 170.666667h682.666666z" p-id="5116" fill="#7162AD"></path></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1721877281911" class="icon" viewBox="0 0 1036 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2369" xmlns:xlink="http://www.w3.org/1999/xlink" width="202.34375" height="200"><path d="M759.466667 827.733333H98.133333c-55.466667 0-98.133333-42.666667-98.133333-98.133333V328.533333c0-55.466667 42.666667-98.133333 98.133333-98.133333h827.733334c55.466667 0 98.133333 42.666667 98.133333 98.133333v234.666667c0 12.8-8.533333 21.333333-21.333333 21.333333s-21.333333-8.533333-21.333334-21.333333V328.533333c0-29.866667-25.6-55.466667-55.466666-55.466666H98.133333C68.266667 273.066667 42.666667 298.666667 42.666667 328.533333V725.333333c0 29.866667 25.6 55.466667 55.466666 55.466667h661.333334c12.8 0 21.333333 8.533333 21.333333 21.333333s-8.533333 25.6-21.333333 25.6z" fill="#7162AD" p-id="2370"></path><path d="M917.333333 827.733333H823.466667c-12.8 0-21.333333-8.533333-21.333334-21.333333s8.533333-21.333333 21.333334-21.333333h93.866666c34.133333 0 64-29.866667 64-64v-85.333334c0-12.8 8.533333-21.333333 21.333334-21.333333s21.333333 8.533333 21.333333 21.333333v85.333334c0 55.466667-46.933333 106.666667-106.666667 106.666666z" fill="#A495FC" p-id="2371"></path><path d="M512 554.666667c-12.8 0-29.866667-4.266667-42.666667-8.533334L17.066667 358.4c-12.8-4.266667-17.066667-17.066667-12.8-29.866667 4.266667-12.8 17.066667-17.066667 29.866666-12.8l456.533334 187.733334c17.066667 8.533333 34.133333 8.533333 51.2 0l448-187.733334c12.8-4.266667 21.333333 0 29.866666 12.8 4.266667 12.8 0 21.333333-12.8 29.866667l-448 187.733333c-21.333333 8.533333-34.133333 8.533333-46.933333 8.533334z" fill="#7162AD" p-id="2372"></path></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

@ -1,5 +0,0 @@
OpenMoji
https://openmoji.org
Licensed under Attribution-ShareAlike 4.0 International
https://creativecommons.org/licenses/by-sa/4.0/

@ -1,5 +0,0 @@
Bootstrap Icons
https://icons.getbootstrap.com
Licensed under MIT license
https://github.com/twbs/icons/blob/main/LICENSE.md

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/>
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/>
</svg>

Before

Width:  |  Height:  |  Size: 352 B

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z"/>
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z"/>
</svg>

Before

Width:  |  Height:  |  Size: 359 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M8 19.9967V14.9967H10V19.9967H19V12.9967H5V19.9967H8ZM4 10.9967H20V7.9967H14V3.9967H10V7.9967H4V10.9967ZM3 20.9967V12.9967H2V6.9967C2 6.44442 2.44772 5.9967 3 5.9967H8V2.9967C8 2.44442 8.44772 1.9967 9 1.9967H15C15.5523 1.9967 16 2.44442 16 2.9967V5.9967H21C21.5523 5.9967 22 6.44442 22 6.9967V12.9967H21V20.9967C21 21.549 20.5523 21.9967 20 21.9967H4C3.44772 21.9967 3 21.549 3 20.9967Z"></path></svg>

Before

Width:  |  Height:  |  Size: 491 B

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chat-square-quote" viewBox="0 0 16 16">
<path d="M14 1a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1h-2.5a2 2 0 0 0-1.6.8L8 14.333 6.1 11.8a2 2 0 0 0-1.6-.8H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2.5a1 1 0 0 1 .8.4l1.9 2.533a1 1 0 0 0 1.6 0l1.9-2.533a1 1 0 0 1 .8-.4H14a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z"/>
<path d="M7.066 4.76A1.665 1.665 0 0 0 4 5.668a1.667 1.667 0 0 0 2.561 1.406c-.131.389-.375.804-.777 1.22a.417.417 0 1 0 .6.58c1.486-1.54 1.293-3.214.682-4.112zm4 0A1.665 1.665 0 0 0 8 5.668a1.667 1.667 0 0 0 2.561 1.406c-.131.389-.375.804-.777 1.22a.417.417 0 1 0 .6.58c1.486-1.54 1.293-3.214.682-4.112z"/>
</svg>

Before

Width:  |  Height:  |  Size: 735 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-down" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/>
</svg>

Before

Width:  |  Height:  |  Size: 290 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-code" viewBox="0 0 16 16">
<path d="M5.854 4.854a.5.5 0 1 0-.708-.708l-3.5 3.5a.5.5 0 0 0 0 .708l3.5 3.5a.5.5 0 0 0 .708-.708L2.707 8l3.147-3.146zm4.292 0a.5.5 0 0 1 .708-.708l3.5 3.5a.5.5 0 0 1 0 .708l-3.5 3.5a.5.5 0 0 1-.708-.708L13.293 8l-3.147-3.146z"/>
</svg>

Before

Width:  |  Height:  |  Size: 362 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M8.58564 8.85449L3.63589 13.8042L8.83021 18.9985L9.99985 18.9978V18.9966H11.1714L14.9496 15.2184L8.58564 8.85449ZM9.99985 7.44027L16.3638 13.8042L19.1922 10.9758L12.8283 4.61185L9.99985 7.44027ZM13.9999 18.9966H20.9999V20.9966H11.9999L8.00229 20.9991L1.51457 14.5113C1.12405 14.1208 1.12405 13.4877 1.51457 13.0971L12.1212 2.49053C12.5117 2.1 13.1449 2.1 13.5354 2.49053L21.3136 10.2687C21.7041 10.6592 21.7041 11.2924 21.3136 11.6829L13.9999 18.9966Z"></path></svg>

Before

Width:  |  Height:  |  Size: 555 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-break"><path d="M0 10.5a.5.5 0 0 1 .5-.5h15a.5.5 0 0 1 0 1H.5a.5.5 0 0 1-.5-.5zM12 0H4a2 2 0 0 0-2 2v7h1V2a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1v7h1V2a2 2 0 0 0-2-2zm2 12h-1v2a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-2H2v2a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-2z"/></svg>

Before

Width:  |  Height:  |  Size: 348 B

@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-journal-code" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8.646 5.646a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L10.293 8 8.646 6.354a.5.5 0 0 1 0-.708zm-1.292 0a.5.5 0 0 0-.708 0l-2 2a.5.5 0 0 0 0 .708l2 2a.5.5 0 0 0 .708-.708L5.707 8l1.647-1.646a.5.5 0 0 0 0-.708z"/>
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2z"/>
<path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1z"/>
</svg>

Before

Width:  |  Height:  |  Size: 772 B

@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-journal-text" viewBox="0 0 16 16">
<path d="M5 10.5a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5zm0-2a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5zm0-2a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5zm0-2a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5z"/>
<path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2z"/>
<path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1z"/>
</svg>

Before

Width:  |  Height:  |  Size: 759 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-justify" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M2 12.5a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 414 B

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-link" viewBox="0 0 16 16">
<path d="M6.354 5.5H4a3 3 0 0 0 0 6h3a3 3 0 0 0 2.83-4H9c-.086 0-.17.01-.25.031A2 2 0 0 1 7 10.5H4a2 2 0 1 1 0-4h1.535c.218-.376.495-.714.82-1z"/>
<path d="M9 5.5a3 3 0 0 0-2.83 4h1.098A2 2 0 0 1 9 6.5h3a2 2 0 1 1 0 4h-1.535a4.02 4.02 0 0 1-.82 1H12a3 3 0 1 0 0-6H9z"/>
</svg>

Before

Width:  |  Height:  |  Size: 403 B

@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-list-ol" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5z"/>
<path d="M1.713 11.865v-.474H2c.217 0 .363-.137.363-.317 0-.185-.158-.31-.361-.31-.223 0-.367.152-.373.31h-.59c.016-.467.373-.787.986-.787.588-.002.954.291.957.703a.595.595 0 0 1-.492.594v.033a.615.615 0 0 1 .569.631c.003.533-.502.8-1.051.8-.656 0-1-.37-1.008-.794h.582c.008.178.186.306.422.309.254 0 .424-.145.422-.35-.002-.195-.155-.348-.414-.348h-.3zm-.004-4.699h-.604v-.035c0-.408.295-.844.958-.844.583 0 .96.326.96.756 0 .389-.257.617-.476.848l-.537.572v.03h1.054V9H1.143v-.395l.957-.99c.138-.142.293-.304.293-.508 0-.18-.147-.32-.342-.32a.33.33 0 0 0-.342.338v.041zM2.564 5h-.635V2.924h-.031l-.598.42v-.567l.629-.443h.635V5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 983 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-list-ul" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm-3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/>
</svg>

Before

Width:  |  Height:  |  Size: 447 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M5 4.9967V7.9967H19V4.9967H5ZM4 2.9967H20C20.5523 2.9967 21 3.44442 21 3.9967V8.9967C21 9.54899 20.5523 9.9967 20 9.9967H4C3.44772 9.9967 3 9.54899 3 8.9967V3.9967C3 3.44442 3.44772 2.9967 4 2.9967ZM6 11.9967H12C12.5523 11.9967 13 12.4444 13 12.9967V15.9967H14V21.9967H10V15.9967H11V13.9967H5C4.44772 13.9967 4 13.549 4 12.9967V10.9967H6V11.9967ZM17.7322 13.7289L19.5 11.9612L21.2678 13.7289C22.2441 14.7052 22.2441 16.2882 21.2678 17.2645C20.2915 18.2408 18.7085 18.2408 17.7322 17.2645C16.7559 16.2882 16.7559 14.7052 17.7322 13.7289Z"></path></svg>

Before

Width:  |  Height:  |  Size: 640 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil-fill" viewBox="0 0 16 16">
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
</svg>

Before

Width:  |  Height:  |  Size: 589 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-plus"><path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/></svg>

Before

Width:  |  Height:  |  Size: 223 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-text-center" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M4 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 416 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-text-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M2 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 412 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-text-paragraph" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M2 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm4-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 417 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-text-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M6 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-4-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm4-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-4-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/>
</svg>

Before

Width:  |  Height:  |  Size: 415 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-type-bold" viewBox="0 0 16 16">
<path d="M8.21 13c2.106 0 3.412-1.087 3.412-2.823 0-1.306-.984-2.283-2.324-2.386v-.055a2.176 2.176 0 0 0 1.852-2.14c0-1.51-1.162-2.46-3.014-2.46H3.843V13H8.21zM5.908 4.674h1.696c.963 0 1.517.451 1.517 1.244 0 .834-.629 1.32-1.73 1.32H5.908V4.673zm0 6.788V8.598h1.73c1.217 0 1.88.492 1.88 1.415 0 .943-.643 1.449-1.832 1.449H5.907z"/>
</svg>

Before

Width:  |  Height:  |  Size: 470 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-type-h1" viewBox="0 0 16 16">
<path d="M8.637 13V3.669H7.379V7.62H2.758V3.67H1.5V13h1.258V8.728h4.62V13h1.259zm5.329 0V3.669h-1.244L10.5 5.316v1.265l2.16-1.565h.062V13h1.244z"/>
</svg>

Before

Width:  |  Height:  |  Size: 282 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-type-h2" viewBox="0 0 16 16">
<path d="M7.638 13V3.669H6.38V7.62H1.759V3.67H.5V13h1.258V8.728h4.62V13h1.259zm3.022-6.733v-.048c0-.889.63-1.668 1.716-1.668.957 0 1.675.608 1.675 1.572 0 .855-.554 1.504-1.067 2.085l-3.513 3.999V13H15.5v-1.094h-4.245v-.075l2.481-2.844c.875-.998 1.586-1.784 1.586-2.953 0-1.463-1.155-2.556-2.919-2.556-1.941 0-2.966 1.326-2.966 2.74v.049h1.223z"/>
</svg>

Before

Width:  |  Height:  |  Size: 482 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-type-h3" viewBox="0 0 16 16">
<path d="M7.637 13V3.669H6.379V7.62H1.758V3.67H.5V13h1.258V8.728h4.62V13h1.259zm3.625-4.272h1.018c1.142 0 1.935.67 1.949 1.674.013 1.005-.78 1.737-2.01 1.73-1.08-.007-1.853-.588-1.935-1.32H9.108c.069 1.327 1.224 2.386 3.083 2.386 1.935 0 3.343-1.155 3.309-2.789-.027-1.51-1.251-2.16-2.037-2.249v-.068c.704-.123 1.764-.91 1.723-2.229-.035-1.353-1.176-2.4-2.954-2.385-1.873.006-2.857 1.162-2.898 2.358h1.196c.062-.69.711-1.299 1.696-1.299.998 0 1.695.622 1.695 1.525.007.922-.718 1.592-1.695 1.592h-.964v1.074z"/>
</svg>

Before

Width:  |  Height:  |  Size: 646 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-type-italic" viewBox="0 0 16 16">
<path d="M7.991 11.674 9.53 4.455c.123-.595.246-.71 1.347-.807l.11-.52H7.211l-.11.52c1.06.096 1.128.212 1.005.807L6.57 11.674c-.123.595-.246.71-1.346.806l-.11.52h3.774l.11-.52c-1.06-.095-1.129-.211-1.006-.806z"/>
</svg>

Before

Width:  |  Height:  |  Size: 351 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-type-strikethrough" viewBox="0 0 16 16">
<path d="M6.333 5.686c0 .31.083.581.27.814H5.166a2.776 2.776 0 0 1-.099-.76c0-1.627 1.436-2.768 3.48-2.768 1.969 0 3.39 1.175 3.445 2.85h-1.23c-.11-1.08-.964-1.743-2.25-1.743-1.23 0-2.18.602-2.18 1.607zm2.194 7.478c-2.153 0-3.589-1.107-3.705-2.81h1.23c.144 1.06 1.129 1.703 2.544 1.703 1.34 0 2.31-.705 2.31-1.675 0-.827-.547-1.374-1.914-1.675L8.046 8.5H1v-1h14v1h-3.504c.468.437.675.994.675 1.697 0 1.826-1.436 2.967-3.644 2.967z"/>
</svg>

Before

Width:  |  Height:  |  Size: 579 B

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-type-underline" viewBox="0 0 16 16">
<path d="M5.313 3.136h-1.23V9.54c0 2.105 1.47 3.623 3.917 3.623s3.917-1.518 3.917-3.623V3.136h-1.23v6.323c0 1.49-.978 2.57-2.687 2.57-1.709 0-2.687-1.08-2.687-2.57V3.136zM12.5 15h-9v-1h9v1z"/>
</svg>

Before

Width:  |  Height:  |  Size: 334 B

@ -1 +0,0 @@
<svg class="prefix__icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M513.554 814.327h-.124a307.518 307.518 0 01-156.195-42.549l-11.211-6.638-116.136 30.331 31.002-112.71-7.291-11.547a303.616 303.616 0 01-46.928-162.533c.071-168.395 137.728-305.382 307.006-305.382a305.54 305.54 0 01216.947 89.565 302.822 302.822 0 0189.794 216.064c-.07 168.395-137.71 305.4-306.864 305.4zM774.727 249.01c-69.72-69.456-162.446-107.75-261.173-107.768-203.53 0-369.135 164.83-369.223 367.405a365.462 365.462 0 0049.293 183.702l-52.383 190.41 195.726-51.093a370.353 370.353 0 00176.428 44.72h.159c203.476 0 369.116-164.846 369.205-367.44.035-98.162-38.33-190.499-108.05-259.954z" fill="#25D366"/><path d="M379.339 686.963c-4.184-2.437-8.263-4.555-8.263-17.814.106-65.713.212-217.689 0-273.885-.106-35.399-4.837-58.297 26.43-58.297 84.568 0 208.155-15.678 236.933 53.53 29.025 69.968-17.938 103.883-28.249 121.891 70.48 19.51 74.346 175.952-76.305 175.952-32.239 0-77.577.106-130.119.212-12.359 0-17.832 0-20.427-1.59zm65.236-57.344h76.5c32.574-.106 61.581-15.042 60.822-47.069-.53-30.102-20.833-40.06-49.1-42.814-26.764.318-57.484.318-88.222.318v89.565zm0-150.07c56.62-.758 78.442 2.208 109.391-5.42 21.275-11.864 30.508-56.072.106-71.008-21.062-10.4-83.597-6.886-109.497-5.827v82.238z" fill="#25D366"/></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@ -1 +0,0 @@
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M16.065 29.045h-.005a13.27 13.27 0 01-6.74-1.836l-.484-.287-5.012 1.31 1.338-4.865-.315-.498a13.102 13.102 0 01-2.025-7.014C2.825 8.588 8.766 2.676 16.071 2.676a13.185 13.185 0 019.362 3.866 13.068 13.068 0 013.875 9.324c-.003 7.267-5.943 13.18-13.243 13.18zM27.336 4.65A15.868 15.868 0 0016.066 0C7.281-.002.135 7.111.131 15.853a15.771 15.771 0 002.127 7.927l-2.26 8.217 8.446-2.205a15.982 15.982 0 007.614 1.93h.006c8.781 0 15.93-7.114 15.933-15.856a15.724 15.724 0 00-4.663-11.219z" fill="#25D366"/><path d="M10.273 23.549c-.18-.105-.356-.197-.356-.769.004-2.836.009-9.394 0-11.82-.005-1.527-.209-2.515 1.14-2.515 3.65 0 8.983-.677 10.225 2.31 1.253 3.02-.774 4.483-1.219 5.26 3.042.842 3.208 7.593-3.293 7.593-1.391 0-3.348.005-5.615.01-.533 0-.77 0-.882-.07zm2.816-2.475h3.301c1.406-.004 2.657-.649 2.625-2.031-.023-1.3-.9-1.729-2.12-1.848-1.154.014-2.48.014-3.806.014v3.865zm0-6.476c2.443-.033 3.385.095 4.72-.234.918-.512 1.317-2.42.005-3.064-.909-.45-3.608-.297-4.725-.252v3.55z" fill="#25D366"/></svg>

@ -1,33 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<svg viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g transform="translate(0, 0)">
<g transform="matrix(1.3809472322464, 0, 0, 1.3809472322464, 0, 0)">
<g transform="translate(0, 0)">
<g transform="matrix(0.827589750289917, 0, 0, 0.827589750289917, 0, 0)">
<g class="prefix__icon" transform="translate(-5.3347, -5.3347)">
<g transform="matrix(1.20832681655884, 0, 0, 1.20832681655884, 0, 0)">
<g transform="matrix(0.03125, 0, 0, 0.03125, 0, 0)">
<path d="M513.554, 814.327L513.43, 814.327A307.518 307.518 0 0 1 357.235, 771.778L346.024, 765.14L229.888, 795.471L260.89, 682.761L253.599, 671.214A303.616 303.616 0 0 1 206.671, 508.681C206.742, 340.286 344.399, 203.299 513.677, 203.299A305.54 305.54 0 0 1 730.624, 292.864A302.822 302.822 0 0 1 820.418, 508.928C820.348, 677.323 682.708, 814.328 513.554, 814.328zM774.727, 249.01C705.007, 179.554 612.281, 141.26 513.554, 141.242C310.024, 141.242 144.419, 306.072 144.331, 508.647A365.462 365.462 0 0 0 193.624, 692.349L141.241, 882.759L336.967, 831.666A370.353 370.353 0 0 0 513.395, 876.386L513.554, 876.386C717.03, 876.386 882.67, 711.54 882.759, 508.946C882.794, 410.784 844.429, 318.447 774.709, 248.992z" fill="#25D366" />
</g>
</g>
</g>
</g>
</g>
</g>
</g>
<g transform="translate(-2.67028807954262E-07, -8.39233399219097E-07)">
<g transform="matrix(1.3809472322464, 0, 0, 1.3809472322464, 0, 0)">
<g transform="translate(1.33514403977131E-07, 1.71661376668908E-07)">
<g transform="matrix(0.827589750289917, 0, 0, 0.827589750289917, 0, 0)">
<g class="prefix__icon" transform="translate(-5.33470045776367, -5.33470049591064)">
<g transform="matrix(1.20832681655884, 0, 0, 1.20832681655884, 0, 0)">
<g transform="matrix(0.03125, 0, 0, 0.03125, 0, 0)">
<path d="M379.339, 686.963C375.155, 684.526 371.076, 682.408 371.076, 669.149C371.182, 603.436 371.288, 451.46 371.076, 395.264C370.97, 359.865 366.239, 336.967 397.506, 336.967C482.074, 336.967 605.661, 321.289 634.439, 390.497C663.464, 460.465 616.501, 494.38 606.19, 512.388C676.67, 531.898 680.536, 688.34 529.885, 688.34C497.646, 688.34 452.308, 688.446 399.766, 688.552C387.407, 688.552 381.934, 688.552 379.339, 686.962zM444.575, 629.619L521.075, 629.619C553.649, 629.513 582.656, 614.577 581.897, 582.55C581.367, 552.448 561.064, 542.49 532.797, 539.736C506.033, 540.054 475.313, 540.054 444.575, 540.054L444.575, 629.619zM444.575, 479.549C501.195, 478.791 523.017, 481.757 553.966, 474.129C575.241, 462.265 584.474, 418.057 554.072, 403.121C533.01, 392.721 470.475, 396.235 444.575, 397.294L444.575, 479.532z" fill="#25D366" />
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

@ -9,14 +9,6 @@ export const fetchSalesAgent = async (q) => {
return errcode !== 0 ? [] : result.map((ele) => ({ ...ele, label: ele.cn_name, value: ele.op_id }));
};
/**
* 绑定钉钉的顾问列表
*/
export const fetchSalesAgentWithDD = async (q) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/opi_with_dingtalk`, { q });
return errcode !== 0 ? [] : result.map((ele) => ({ ...ele, label: ele.cn_name, value: ele.op_id, key: ele.op_id }));
};
/**
* 客人列表
*/

@ -1,161 +1,55 @@
import { groupBy, isNotEmpty, pick, sortArrayByOrder, sortBy } from '@/utils/commons';
import { fetchJSON, postJSON, postForm } from '@/utils/request'
import { parseRenderMessageList } from '@/channel/bubbleMsgUtils';
import { groupBy, pick, sortArrayByOrder } from '@/utils/commons';
import { fetchJSON, postJSON } from '@/utils/request'
import { parseRenderMessageList } from '@/channel/whatsappUtils';
import { API_HOST } from '@/config';
import { isEmpty } from '@/utils/commons';
import dayjs from 'dayjs';
/**
* @param {object} params { waba }
*/
export const fetchTemplates = async (params) => {
const data = await fetchJSON(`${API_HOST}/listtemplates`, params);
const topName = [
'agent_intro_with_update_v1',
'online_inquiry_received',
'say_hello_again',
'order_updated_specialist_assigned_christy',
'order_resumed_specialist_followup_schedule_sharon',
'travel_service_update_v2',
'travel_service_update_v1',
'order_updated_specialist_assigned_sharon',
'first_message_for_not_reply',
// 'free_style_3',
// 'free_style_4',
];
// shouwcase
const scNames = ['trip_planner_showcase', 'showcase_different', 'order_status_updated'];
// 客运
const crNames = [
'notification_of_next_trip_planning',
// 'notification_of_following_up_by_cr_v3',
'notification_of_one_day_before_ending_the_trip_by_cr_v2',
'one_day_after_payment_by_yuni',
'notification_of_status_changed',
'notification_of_one_day_before_ending_the_trip_by_cr','one_day_after_payment_by_customer_relations',
'one_day_before_ending_the_trip_contacted_by_yuni','one_day_before_ending_the_trip_first_time_by_yuni',
'post_booking_confirmation_welcome',
];
const crNamesOmit = [
'birthday_greetings_by_marketing','one_day_before_ending_the_trip_by_marketing',
'introduce_the_voucher_one_day_before_ending_the_trip_by_marketing',
'birthday_greetings_by_customer_relations_0',
'post_trip_voucher_issued',
'account_updated_order_ref',
'post_trip_account_updated_from_cr',
'post_trip_account_updated',
'account_update_birthday',
'post_trip_birthday_reward',
'birthday_greetings_by_customer_relations_2',
'birthday_greetings_by_customer_relations_1',
'notification_of_account_updated_by_cr',
'birthday_greetings_by_customer_relations',
'one_day_before_ending_the_trip_by_customer_relations',
]
export const fetchTemplates = async () => {
const data = await fetchJSON(`${API_HOST}/listtemplates`);
const canUseTemplates = (data?.result?.items || [])
.filter((_t) => _t.status === 'APPROVED' && !['say_hello_from_trip_advisor', 'free_style_7', 'free_style_1', 'free_style_2'].includes(_t.name))
.map((ele, i) => ({
...ele,
components_origin: ele.components,
components: groupBy(ele.components, (_c) => _c.type.toLowerCase()),
key: ele.name,
// displayName: ele.name.startsWith('order_updated') ? templatesDisplayNameMap['order_updated']+`_${i}` : templatesDisplayNameMap?.[ele.name] || ele.name,
displayName: templatesDisplayNameMap?.[ele.name] || (ele.name.startsWith('order_updated') ? templatesDisplayNameMap['order_updated']+`_${i}` : ele.name),
displayLanguage: crNamesOmit.includes(ele.name) ? '客运-' : (crNames.includes(ele.name) || ele.name.includes('by_cr')) ? ele.language + '-客运' : scNames.includes(ele.name) ? ele.language + '-示例' : ele.language,
}))
const top2Name = topName.concat(canUseTemplates.filter(_t => _t.name.startsWith('order_updated')).map(_tem => _tem.name));
const top = sortArrayByOrder( canUseTemplates.filter((_t) => top2Name.includes(_t.name)), 'name', topName);
const second = canUseTemplates.filter(_t => _t.name.includes('free_style'));
const secondS = second.sort(sortBy('name'));
const raw = canUseTemplates.filter((_t) => !top2Name.includes(_t.name) && !_t.name.includes('free_style'));
// 剩下的排序
const rawS = sortArrayByOrder(raw, 'name', [...crNames, ...scNames, ...crNamesOmit ]);
return [...top, ...secondS, ...rawS];
};
/**
* 上面的模板名称bak
* order_updated_specialist_assigned_sharon : free_style_7
* order_updated_specialist_assigned_christy : free_style_1
* online_inquiry_received: say_hello_from_trip_advisor
* order_resumed_specialist_followup_schedule_sharon: free_style_2
*/
const templatesDisplayNameMap = {
'order_updated_specialist_assigned_sharon': 'specialist_followup',
'order_updated_specialist_assigned_christy': 'specialist_followup_1',
'online_inquiry_received': 'online_inquiry_received/say_hello',
'order_resumed_specialist_followup_schedule_sharon': 'order_resumed/specialist_followup',
'order_updated': 'specialist_followup',
'agent_intro_with_update_v1': 'quick_update_v1',
.filter((_t) => _t.status === 'APPROVED')
.map((ele) => ({ ...ele, components_origin: ele.components, components: groupBy(ele.components, (_c) => _c.type.toLowerCase()) }));
const topName = ['say_hello_from_trip_advisor', 'free_style_7', 'free_style_2', 'free_style_1', 'free_style_3', 'free_style_4'];
const top = sortArrayByOrder( canUseTemplates.filter((_t) => topName.includes(_t.name)), 'name', topName);
const raw = canUseTemplates.filter((_t) => !topName.includes(_t.name));
return [...top, ...raw];
};
export const CONVERSATION_PAGE_SIZE = 100;
/**
*
* @param {object} params { opisn }
*/
export const fetchConversationsList = async (params) => {
const defaultParams = {
opisn: '',
pagesize: CONVERSATION_PAGE_SIZE,
lastpagetime: '',
tags: '',
olabel: '',
keyword: '',
ostate: '',
intour: '',
session_enable: 1,
lastactivetime: '',
top_state: '',
}
const combinedFilterStr = Object.values(pick(params, ['keyword', 'tags', 'olabel', 'intour', 'ostate'])).join('')
if (isNotEmpty(combinedFilterStr) || params.session_enable === 0) {
params.lastactivetime = '';
}
const { errcode, result: data } = await fetchJSON(`${API_HOST}/getconversations`, { ...defaultParams, ...params })
const { errcode, result: data } = await fetchJSON(`${API_HOST}/getconversations`, params);
if (errcode !== 0) return [];
const list = (data || []).map((ele) => ({
...ele,
customer_name: `${ele.whatsapp_name || ''}`.trim(),
whatsapp_name: `${ele.whatsapp_name || ''}`.trim(),
show_default: ele.conversation_memo || ele.whatsapp_name || ele?.channels?.whatsapp_phone_number || ele?.channels?.phone_number || ele?.channels?.email || '',
// coli_id: ele.COLI_ID,
top_state: ele.top_state || 0,
}))
const list = (data || []).map((ele) => ({ ...ele, customer_name: `${ele.whatsapp_name || ''}`.trim(), whatsapp_name: `${ele.whatsapp_name || ''}`.trim() }));
return list;
};
/**
*
* @param {object} params { opisn, whatsappid, colisn, email }
* @param {object} params { opisn, whatsappid, colisn }
* * opisn, colisn : 用于查询
* * whatsappid, email: 用于创建会话
* * whatsappid: 用于创建会话
*/
export const fetchOrderConversationsList = async (params) => {
const { errcode, result: data } = await fetchJSON(`${API_HOST}/getorderconversation`, params);
if (errcode !== 0) return [];
const list = data.map((ele) => ({
...ele,
customer_name: `${ele.whatsapp_name || ''}`.trim(),
whatsapp_name: `${ele.whatsapp_name || ''}`.trim(),
show_default: ele.conversation_memo || ele.whatsapp_name || ele?.channels?.whatsapp_phone_number || ele?.channels?.phone_number || ele?.channels?.email || '',
}))
const list = data.map((ele) => ({ ...ele, customer_name: `${ele.whatsapp_name || ''}`.trim(), whatsapp_name: `${ele.whatsapp_name || ''}`.trim() }));
return list;
};
export const MESSAGE_PAGE_SIZE = 50;
/**
*
* @param {object} params { coli_sn, opisn, whatsappid, conversationid, lasttime, pagesize }
* @param {object} params { opisn, whatsappid, lasttime, pagesize }
*/
export const fetchMessages = async (params) => {
const defaultParams = {
// opisn: '',
// whatsappid: '',
coli_sn: '',
conversationid: '',
opisn: '',
whatsappid: '',
lasttime: '',
pagesize: MESSAGE_PAGE_SIZE,
};
@ -175,63 +69,19 @@ export const fetchConversationItemClose = async (body) => {
/**
* @param {object} body { phone_number, name }
*/
export const postNewOrEditConversationItem = async (body) => {
body.whatsapp_phone_number = `${body.whatsapp_phone_number || ''}`.trim();
const formData = new FormData();
Object.keys(body).forEach(function (key) {
formData.append(key, body[key]);
});
const { errcode, result } = await postForm(`${API_HOST}/new_conversation`, formData);
if (errcode !== 0) {
return {};
}
const resultItem = result?.[0] || {};
return {
...resultItem,
customer_name: `${resultItem.whatsapp_name || ''}`.trim(),
whatsapp_name: `${resultItem.whatsapp_name || ''}`.trim(),
// channels: {},
// tags: [],
// last_message: {},
top_state: 0,
// conversation_memo: resultItem.session_memo,
};
};
/**
* @param {object} params { conversationid, coli_sn }
*/
export const postEditConversationItemColiAction = async (params) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/update_conversation_orderid`, params);
export const postNewConversationItem = async (body) => {
const { errcode, result } = await postJSON(`${API_HOST}/newconversation`, body);
return errcode !== 0 ? {} : result;
};
/**
* @param {object} params { opisn, conversationid }
* @param {object} params { opisn, whatsappid }
*/
export const fetchCleanUnreadMsgCount = async (params) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/clean_unread_msg_count`, params);
return errcode !== 0 ? {} : result;
};
/**
* 标记未未读
* @param {object} body conversationItem: { sn, ... }
*/
export const UNREAD_MARK = 999;
export const fetchConversationItemUnread = async (body) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/set_state_unread`, body);
return errcode !== 0 ? {} : result;
};
/**
* 设置置顶
* @param {object} body { conversationid, top_state }
*/
export const fetchConversationItemTop = async (body) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/set_top_conversation`, body);
return errcode !== 0 ? {} : result;
};
/**
* ------------------------------------------------------------------------------------------------
* 历史记录
@ -247,16 +97,12 @@ export const fetchConversationsSearch = async (params) => {
? []
: (data || []).map((ele) => ({
...ele,
sn: ele.conversationid,
customer_name: `${ele.whatsapp_name || ''}`.trim(),
whatsapp_name: `${ele.whatsapp_name || ''}`.trim(),
opi_sn: ele.OPI_SN || ele.opi_sn || 0,
OPI_Name: `${ele.OPI_Name || ele.opi_name || ''}`.trim(),
opi_name: `${ele.OPI_Name || ele.opi_name || ''}`.trim(),
dateText: dayjs((ele.lasttime)).format('MM-DD HH:mm'),
dateText: dayjs((ele.last_received_time || ele.last_send_time)).format('MM-DD HH:mm'),
matchMsgList: parseRenderMessageList((ele.msglist_AsJOSN || [])), // .reverse()),
coli_id: '',
show_default: ele.session_memo || ele.whatsapp_name || ele?.whatsapp_phone_number || ele?.guest_email || '',
}));
return list;
};
@ -267,88 +113,17 @@ export const fetchConversationsSearch = async (params) => {
*/
export const fetchMessagesHistory = async (params) => {
const defaultParams = {
// opisn: '',
// whatsappid: '',
conversationid: '',
opisn: '',
whatsappid: '',
lasttime: '2024-01-01T00:00:00',
pagesize: MESSAGE_PAGE_SIZE,
pagedir: 'next',
};
const _params = pick(params, Object.keys(defaultParams));
if (isEmpty(_params.conversationid)) {
if (isEmpty(_params.opisn) || isEmpty(_params.whatsappid)) {
return [];
}
const { errcode, result } = await fetchJSON(`${API_HOST}/get_item_messages`, {...defaultParams, ..._params});
const data = errcode !== 0 ? [] : result; // _params.pagedir === 'next' ? result.reverse() : result;
return parseRenderMessageList(data);
}
/**
* @param {object} params { opisn, phone_number_from, phone_number_mergeto }
*/
export const fetchConversationMerge = async (params) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/merge_session`, params);
return errcode !== 0 ? {} : result;
};
/**
* ------------------------------------------------------------------------------------------------
* 未分配
*/
export const fetchConversationsUnassigned = async (params) => {
const { errcode, result: data } = await fetchJSON(`${API_HOST}/unassigned-conversation`, params);
const list =
errcode !== 0
? []
: (data || []).map((ele) => ({
...ele,
customer_name: `${ele.whatsapp_name || ''}`.trim(),
whatsapp_name: `${ele.whatsapp_name || ''}`.trim(),
opi_sn: ele.OPI_SN || ele.opi_sn || 0,
OPI_Name: `${ele.OPI_Name || ele.opi_name || ''}`.trim(),
dateText: dayjs((ele.last_received_time)).format('MM-DD HH:mm'),
}));
return list;
};
/**
* @param {object} params { opi_sn, conversationid }
*/
export const postAssignConversation = async (params) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/assign_conversation`, params);
return errcode !== 0 ? {} : result;
}
/**
* ------------------------------------------------------------------------------------------------
*
*/
/**
* 顾问的自定义标签
* @param {object} params { opisn, }
*/
export const fetchTags = async (params) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/get_opi_tags`, params);
return errcode !== 0 ? [] : result.map(ele => ({ label: ele.tag_label, key: ele.tag_key, value: ele.tag_key, }));
}
/**
* 会话设置标签
* @param {object} body { opisn, conversationid, tag_label, tag_id }
*/
export const postConversationTags = async (body) => {
const formData = new FormData();
Object.keys(body).forEach(function (key) {
formData.append(key, body[key]);
});
const { errcode, result } = await postForm(`${API_HOST}/set_conversation_tags_add`, formData);
return errcode !== 0 ? {} : result[0];
}
/**
* 会话删除标签
* @param {object} params { opisn, conversationid, tag_id }
*/
export const deleteConversationTags = async (params) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/set_conversation_tags_del`, params);
return errcode !== 0 ? {} : result;
}

@ -1,491 +0,0 @@
import { fetchJSON, postForm, postJSON } from '@/utils/request';
import { API_HOST, API_HOST_V3, DATE_FORMAT, DATEEND_FORMAT, DATETIME_FORMAT, EMAIL_HOST, EMAIL_HOST_v3 } from '@/config';
import { buildTree, groupBy, isEmpty, objectMapper, omitEmpty, uniqWith } from '@/utils/commons';
import { readIndexDB, writeIndexDB } from '@/utils/indexedDB';
import dayjs from 'dayjs';
import { internalEventEmitter } from '@/utils/EventEmitterService';
export const parseHTMLString = (html, needText = false) => {
const parser = new DOMParser()
const doc = parser.parseFromString(html, 'text/html')
let bodyContent = doc.body.innerHTML
// bodyContent = bodyContent.replace(/<img/g, '<img onerror="this.onerror=null;this.src=\'https://hiana-crm.oss-accelerate.aliyuncs.com/WAMedia/afe412d4-3acf-4e79-a623-048aeb4d696a.png\';"')
const bodyText = (doc.body.innerText);
return needText ? { html, bodyContent, bodyText } : bodyContent
}
export const EMAIL_CHANNEL_NAME = 'mailbox_changes';
let emailChangesChannel = null;
export function getEmailChangesChannel() {
if (!emailChangesChannel) {
emailChangesChannel = new BroadcastChannel(EMAIL_CHANNEL_NAME)
}
return emailChangesChannel
}
// 通知邮件列表数据更新
const notifyMailboxUpdate = (payload) => {
const notificationPayload = payload
// - 多个tab
const channel = getEmailChangesChannel()
channel.postMessage(notificationPayload)
// - 当前tab
internalEventEmitter.emit(EMAIL_CHANNEL_NAME, notificationPayload)
}
/**
* 获取顾问签名
* @param {object} { opi_sn }
*/
export const getSalesSignatureAction = async (params) => {
try {
const { result } = await fetchJSON(`${EMAIL_HOST}/email_sign`, params)
const { SignContent: html } = result
const bodyContent = parseHTMLString(html);
return bodyContent;
} catch (error) {
return '';
}
};
/**
* 发送邮件
*/
export const postSendEmail = async (body) => {
const { attaList=[], atta, content, ...bodyData } = body;
bodyData.ordertype = 227001;
const formData = new FormData();
Object.keys(bodyData).forEach(function (key) {
formData.append(key, bodyData[key]);
});
attaList.forEach(function (item) {
formData.append('attachment', item);
});
const { result } = await postForm(`${EMAIL_HOST}/sendmail`, formData);
return result;
};
/**
* 重发邮件
* @param {object} { mai_sn }
*/
export const postResendEmailAction = async (body) => {
const { attaList, atta, content, ...bodyData } = body;
const formData = new FormData();
Object.keys(bodyData).forEach(function (key) {
formData.append(key, bodyData[key]);
});
return await postForm(`${EMAIL_HOST}/email_resend`, formData);
};
const encodeEmailInfo = (info) => {
const encodeQuote = (str = '') => str.replace(/"/g, ''); //.replace(/</g,'&lt;').replace(/>/g,'&gt;')
const CSsClean = encodeQuote(info.MAI_CS).includes(',') ? encodeQuote(info.MAI_CS).split(',') : encodeQuote(info.MAI_CS).split(';');
const tosClean = (encodeQuote(info.MAI_To).includes(',') ? encodeQuote(info.MAI_To).split(',') : encodeQuote(info.MAI_To).split(';')).concat(CSsClean).filter(s => s);
const replyTo = info.MAI_Direction === 1 ? info.MAI_To : info.MAI_From;
const replyToAll = (tosClean.length > 1) ?
(info.MAI_Direction === 1 ? tosClean.join(',') : [...tosClean, info.MAI_From].join(','))
: (info.MAI_Direction === 1 ? info.MAI_To : info.MAI_From)
return {
...info,
MAI_From: encodeQuote(info.MAI_From),
MAI_To: encodeQuote(info.MAI_To),
tos: [...new Set(tosClean)],
replyToAll,
replyTo,
}
};
/**
* 邮件详情
* @param {object} { mai_sn }
*/
export const getEmailDetailAction = async (params) => {
// const cacheKey = params.mai_sn;
// const readCache = await readIndexDB(cacheKey, 'mailinfo', 'mailbox');
// if (!isEmpty(readCache)) { // todo: 除了草稿
// return readCache.data;
// }
const { result } = await fetchJSON(`${EMAIL_HOST}/getmail`, params);
let mailType = result.MailInfo?.[0]?.MAI_ContentType || '';
mailType = mailType === '' && (result.MailContent||'').includes('<html') ? 'text/html' : mailType;
const emailInfo = encodeEmailInfo(result.MailInfo?.[0] || {});
const isFromHub = emailInfo.MAI_From.includes('info@chinahighlights.net');
const delLinefeed = mailType === 'text/html' ? (result.MailContent||'').includes('<html') ? true : false : true;
const cleanContent = (result.MailContent || '').replace(/\r\n/g, delLinefeed ? '' : (isFromHub ? '<br>' : ''));
const { html, bodyContent, bodyText } = mailType === 'text/html' ? parseHTMLString(cleanContent, true) : { html: '', bodyContent: '', bodyText: '' };
const attachments = (isEmpty(result?.AttachList) ? [] : result.AttachList).filter(ele => isEmpty(ele.ATI_ContentID) || ele.ATI_ContentID == '0');
const insideAttachments = (isEmpty(result?.AttachList) ? [] : result.AttachList).filter(ele => !isEmpty(ele.ATI_ContentID) && ele.ATI_ContentID != '0');
const ret = {
info: { ...encodeEmailInfo(result.MailInfo?.[0] || {}), mailType },
content: mailType === 'text/html' ? html : result.MailContent || '',
abstract: bodyText || result.MailContent || '',
attachments,
insideAttachments,
AttachList: isEmpty(result?.AttachList) ? [] : result.AttachList,
}
// writeIndexDB([{key: cacheKey, data: ret}], 'mailinfo', 'mailbox')
return ret;
}
export const getEmailOrderAction = async ({ colisn }) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/getorderinfo`, { colisn })
return errcode === 0 ? { ...result[0], customerDetail: result[0].contact[0] } : {}
}
/**
* 主动收邮件, 单个账户
* @param {object} { opi_sn, }
*/
export const getEmailFetchAction = async (params) => {
const { opi_sn, } = params
const { result } = await fetchJSON(`${EMAIL_HOST}/email_fetch`, {
opi_sn,
})
return result
};
/**
* 报价信邮件草稿
* @param {object} { sfi_sn, coli_sn, lgc }
*/
export const getEmailQuotationDraftAction = async (params) => {
const { result } = await fetchJSON(`${EMAIL_HOST}/QuotationLetter`, params)
return { subject: (result.Subject || ''), content: parseHTMLString((result.MailContent || '').replace(/\r\n/g, '')) }
}
/**
* 单个邮件绑定订单
* @param {object} { conversationid, mai_sn, coli_sn, coli_id, sourcetype }
*/
export const fetchEmailBindOrderAction = async (params) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/mailinfo_bindorder`, params)
return errcode === 0 ? true : false;
}
const todoTypes = {
// 1新订单2WhatsApp未读消息3需一催4需二催5需三催6未处理邮件入境提醒coli_ordertype=7余款提醒coli_ordertype=8
1: '新订单',
2: '未读WhatsApp',
3: '一催',
4: '二催',
5: '三催',
6: '老邮件',
7: '入境提醒',
8: '余款提醒',
}
/**
* 顾问的邮箱目录
* @param {object} params { opi_sn, year, by_start_date, by_success, important, if_want_book, if_thinking }
* @param {boolean} retOrder 是否直接返回订单列表 -- 忽略
*/
export const getEmailDirAction = async (params = { opi_sn: '' }, retOrder=false) => {
const defaultParams = { opi_sn: 0, year: dayjs().year(), by_start_date: -1, by_success: -1, important: -1, if_want_book: -1, if_thinking: -1 }
const { errcode, result } = await fetchJSON(`${API_HOST_V3}/email_dir`, { ...defaultParams, ...params })
const mailboxSort = result //.sort(sortBy('MDR_Order'));
let tree = buildTree(mailboxSort, { key: 'VKey', parent: 'VParent', name: 'VName', iconIndex: 'ImageIndex', rootKeys: [1], ignoreKeys: [-227001, -227002] })
tree = tree.filter((ele) => ele.key !== 1)
const retTree = errcode === 0 ? tree : [];
const orderList = groupBy(result, row => `${row.IsTrue}`)?.['0'] || [];
return retOrder !== false ? orderList : { [`${params.opi_sn}`]: retTree }
};
export const getMailboxCountAction = async (params = { opi_sn: '' }, update = true) => {
const defaultParams = {
opi_sn: 0,
// date1: dayjs().subtract(1, 'year').startOf('year').format(DATE_FORMAT),
date1: dayjs().subtract(180, 'days').format(DATE_FORMAT),
date2: dayjs().format(DATEEND_FORMAT)
}
const { errcode, result } = await fetchJSON(`${API_HOST_V3}/dir_count`, {...defaultParams, ...params})
const ret = errcode !== 0 ? { [`${params.opi_sn}`]: {} } : { [`${params.opi_sn}`]: result }
// 更新数量
if (update !== false) {
const readCacheDir = (await readIndexDB(Number(params.opi_sn), 'dirs', 'mailbox')) || {};
const mailboxDir = isEmpty(readCacheDir) ? [] : readCacheDir.tree.filter(node => node?._raw?.IsTrue === 1);
const _MapDir = new Map(mailboxDir.map((obj) => [obj.key, obj]))
Object.keys(result).map(dirKey => {
_MapDir.set(Number(dirKey), {..._MapDir.get(Number(dirKey)), count: result[dirKey]});
})
const _newToUpdate = Array.from(_MapDir.values());
const _MapRoot = new Map((readCacheDir?.tree || []).map((obj) => [obj.key, obj]))
_newToUpdate.forEach((row) => {
_MapRoot.set(row.key, row)
})
const _newRoot = Array.from(_MapRoot.values())
writeIndexDB([{ ...readCacheDir, key: Number(params.opi_sn), tree: _newRoot }], 'dirs', 'mailbox')
notifyMailboxUpdate({ type: 'dirs', key: Number(params.opi_sn) })
}
return ret;
};
export const getTodoOrdersAction = async (params) => {
const opi_arr = params.opisn.split(',')
const defaultStickyTree = opi_arr.reduce(
(a, ele) => ({
...a,
[ele]: [
{
key: ele + '-today',
title: '今日任务',
getMails: false,
iconIndex: 'star',
children: [],
COLI_SN: 0,
},
{
key: ele + '-todo',
title: '待办任务',
getMails: false,
iconIndex: 'calendar',
children: [],
COLI_SN: 0,
},
// {
// key: ele.OPI_DEI_SN + '-reminder',
// title: '催信',
// getMails: false,iconIndex: 'reminder',
// icon: <BellTwoTone />,
// children: [], COLI_SN: 0,
// },
],
}),
{},
)
const { errcode, result } = await fetchJSON(`${API_HOST}/getwlorder`, params)
// 订单重复时, 取后一个状态, 因此翻转两次
const _result_unique = uniqWith(result.reverse(), (a, b) => a.COLI_SN === b.COLI_SN).reverse();
const orderList = errcode === 0 ? _result_unique : []
const byOPI = groupBy(orderList, 'OPI_SN')
const byState = Object.keys(byOPI).reduce((acc, key) => {
const sticky = groupBy(byOPI[key], (ele) => ([1, 6].includes(ele.coli_ordertype) ? 0 : [2, 3, 4, 5].includes(ele.coli_ordertype) ? 1 : 2))
const treeNode = [
{
key: key + '-today',
title: '今日任务',
getMails: false,
iconIndex: 'star',
_raw: { COLI_SN: 0, IsTrue: 0 },
children: (sticky[0] || []).map((o) => ({
key: `today-${o.COLI_SN}`,
title: `(${todoTypes[o.coli_ordertype] || o.COLI_State}) ${o.COLI_ID}`,
iconIndex: 13,
parent: key + '-today',
parentTitle: '今日任务',
parentIconIndex: 'star',
_raw: { ...o, VKey: o.COLI_SN, VName: o.COLI_ID, VParent: key + '-today', IsTrue: 0, ApplyDate: '', OrderSourceType: 227001, parent: key + '-today' },
})),
},
{
key: key + '-todo',
title: '待办任务',
getMails: false,
iconIndex: 'calendar',
_raw: { COLI_SN: 0, IsTrue: 0 },
children: (sticky[2] || []).map((o) => ({
key: `todo-${o.COLI_SN}`,
title: `(${todoTypes[o.coli_ordertype] || o.COLI_State}) ${o.COLI_ID}`,
iconIndex: 13,
parent: key + '-todo',
parentTitle: '待办任务',
parentIconIndex: 'calendar',
_raw: { ...o, VKey: o.COLI_SN, VName: o.COLI_ID, VParent: key + '-todo', IsTrue: 0, ApplyDate: '', OrderSourceType: 227001, parent: key + '-todo' },
})),
},
...(!isEmpty(sticky[1] || [])
? [
{
key: key + '-reminder',
title: '催信',
getMails: false,
iconIndex: 'reminder',
_raw: { COLI_SN: 0, IsTrue: 0 },
children: (sticky[1] || []).map((o) => ({
key: `reminder-${o.COLI_SN}`,
title: `(${todoTypes[o.coli_ordertype] || o.COLI_State}) ${o.COLI_ID}`,
iconIndex: 13,
parent: key + '-reminder',
parentTitle: '催信',
parentIconIndex: 'reminder',
_raw: { ...o, VKey: o.COLI_SN, VName: o.COLI_ID, VParent: key + '-reminder', IsTrue: 0, ApplyDate: '', OrderSourceType: 227001, parent: key + '-reminder' },
})),
},
]
: []),
]
return { ...acc, [key]: treeNode }
}, defaultStickyTree)
return errcode === 0 ? byState : defaultStickyTree
};
/**
* 获取待办目录和邮箱目录
* @param {object} params { opi_sn, userIdStr }
* @param {number} params.opi_sn
* @param {string} params.userIdStr - 用户ID字符串默认为空
*/
export const getRootMailboxDirAction = async ({ opi_sn = 0, userIdStr = '' } = {}) => {
const [stickyTree, ...mailboxDir] = await Promise.all([
getTodoOrdersAction({ opisn: userIdStr || String(opi_sn), otype: 'today' }),
...(userIdStr.split(',').map(_opi => getEmailDirAction({ opi_sn: _opi }))),
])
const mailBoxCount = await Promise.all(userIdStr.split(',').map(_opi => getMailboxCountAction({ opi_sn: _opi }, false)));
const mailboxDirCountByOPI = mailBoxCount.reduce((a, c) => ({ ...a, ...c, }), {})
const mailboxDirByOPI = mailboxDir.reduce((a, c) => ({ ...a, ...(Object.keys(c).reduce((a, opi) => ({...a, [opi]: c[`${opi}`].map((dir) => ({ ...dir, count: mailboxDirCountByOPI[opi][`${dir.key}`] })) }), {} )) }), {})
const rootTree = Object.keys(stickyTree).map((opi) => ({ key: Number(opi), tree: [...stickyTree[opi], ...(mailboxDirByOPI?.[opi] || [])], treeTimestamp: Date.now() }))
writeIndexDB(rootTree, 'dirs', 'mailbox')
const _mapped = groupBy(rootTree, 'key')
return _mapped[opi_sn]?.[0]?.tree || []
}
/**
* 获取邮件列表
* @usage 邮件目录下的邮件列表
* @usage 订单的邮件列表
*/
export const queryEmailListAction = async ({ opi_sn = '', pagesize = 10, last_id = '', node = {}, } = {}) => {
const _params = {
vkey: 0,
vparent: 0,
order_source_type: 0,
// mai_senddate1: dayjs().subtract(1, 'year').startOf('year').format(DATE_FORMAT),
mai_senddate1: dayjs().subtract(180, 'days').format(DATE_FORMAT),
mai_senddate2: dayjs().format(DATEEND_FORMAT),
...omitEmpty({
...node,
opi_sn,
}),
}
_params.mai_senddate1 = dayjs(_params.mai_senddate1).format(DATE_FORMAT)
const cacheKey = isEmpty(_params.coli_sn) ? `dir-${node.vkey}` : `order-${node.vkey}`;
const { errcode, result } = await fetchJSON(`${API_HOST_V3}/mail_list`, _params)
const ret = errcode === 0 ? result : []
if (!isEmpty(ret)) {
const listids = [...new Set(ret.map(ele => ele.MAI_SN))];
writeIndexDB([{key: cacheKey, data: listids}], 'maillist', 'mailbox')
writeIndexDB(ret.map(ele => ({ data: {...ele, listKey: cacheKey }, key: ele.MAI_SN})), 'listrow', 'mailbox')
}
return ret;
}
export const searchEmailListAction = async ({opi_sn = '', mailboxtype = 'ALL', sender = '', receiver = '', subject = '', content=''}={}) => {
const formData = new FormData()
formData.append('opi_sn', opi_sn)
formData.append('mailboxtype', mailboxtype)
formData.append('sender', sender)
formData.append('receiver', receiver)
formData.append('subject', subject)
// formData.append('content', content)
const { errcode, result } = await postForm(`${API_HOST_V3}/mail_search`, formData)
const ret = errcode === 0 ? result : []
notifyMailboxUpdate({ type: 'maillist-search-result', query: [sender, receiver, subject].filter(s => s).join(' '), data: ret.map(ele => ({...ele, key: ele.MAI_SN, showFolder: true })) })
return ret;
}
const removeFromCurrentList = async (params) => {
const readRow0 = await readIndexDB(params.mai_sn_list[0], 'listrow', 'mailbox')
const listKey = readRow0?.data?.listKey || ''
if (listKey) {
const readCache = await readIndexDB(listKey, 'maillist', 'mailbox')
const updatedMailList = readCache.data.filter((mai_sn) => !params.mai_sn_list.includes(mai_sn))
writeIndexDB([{ key: listKey, data: updatedMailList }], 'maillist', 'mailbox')
notifyMailboxUpdate({ type: 'listrow', listKey, affectKeys: params.mai_sn_list })
}
}
const updateEmailKeyMap = { read: 'MOI_ReadState' };
const updateEmailKeyFun = {
read: async (params) => {
const readCache = await readIndexDB(params.mai_sn_list, 'listrow', 'mailbox')
const updateField = Object.keys(params.set).reduce((a, c) => ({ ...a, [updateEmailKeyMap[c]]: params.set[c] }), {})
writeIndexDB(
params.mai_sn_list.map((ele) => ({ data: { ...(readCache.get(ele)?.data || {}), ...updateField }, key: ele })),
'listrow',
'mailbox',
)
// 通知邮件列表数据更新
const listKey = readCache.get(params.mai_sn_list[0])?.data?.listKey || '';
const notificationPayload = { type: 'listrow', listKey, affectKeys: params.mai_sn_list }
notifyMailboxUpdate(notificationPayload)
},
processed: removeFromCurrentList,
delete: removeFromCurrentList
}
/**
* 更新邮件属性
*/
export const updateEmailAction = async (params = { opi_sn: 0, mai_sn_list: [], set: {} }) => {
if (isEmpty(params.mai_sn_list)) {
throw new Error('没有需要更新的邮件');
}
const { errcode, result } = await postJSON(`${API_HOST_V3}/mail_update`, params)
if (errcode === 0 ) {
for (const [key, value] of Object.entries(params.set)) {
const updateFun = updateEmailKeyFun[key] || (() => {});
updateFun(params)
}
}
getMailboxCountAction({ opi_sn: params.opi_sn });
return errcode === 0 ? result : {}
}
/**
* 获取邮件模板
* @param {object} params - Parameters for the email template request.
* @param {number} [params.coli_sn] - Customer order line item serial number.
* @param {number} [params.lgc] - Language code.
* @param {number} [params.opi_sn] - Order product item serial number.
* @param {string} [params.remind_type] - Type of reminder.
* @param {number} [params.remind_index] - Index of the reminder.
*/
export const getReminderEmailTemplateAction = async (params = { coli_sn: 0, lgc: 1, opi_sn: 0, remind_type: '', remind_index: 0 }) => {
const { errcode, result } = await fetchJSON(`${API_HOST_V3}/reminder_letter`, params)
const { html, bodyContent, bodyText } = parseHTMLString(result?.MailContent, true) ;
return errcode === 0 ? {...result, bodyContent }: {}
}
/**
* 保存邮件草稿
* @param {object} body - The body of the email.
* @param {boolean} [isDraft=false] - Whether the email is a draft.
*/
export const saveEmailDraftOrSendAction = async (body, isDraft = false) => {
const url = isDraft !== false ? `${API_HOST_V3}/email_draft_save` : `${EMAIL_HOST_v3}/sendmail`;
const { attaList=[], atta, content, ...bodyData } = body;
bodyData.ordertype = 227001;
const formData = new FormData();
Object.keys(bodyData).forEach(function (key) {
formData.append(key, bodyData[key] || '');
});
// 附件只传新增的
attaList.filter(ele => !ele.fullPath).forEach(function (item) {
formData.append('attachment', item);
});
const { errcode, result } = await postForm(url, formData);
return errcode === 0 ? (result || {}) : {}
};
/**
* 删除邮件附件
*/
export const deleteEmailAttachmentAction = async (ati_sn_list) => {
const { errcode, result } = await postJSON(`${API_HOST_V3}/mail_attachment_delete`, { ati_sn_list })
return errcode === 0 ? result : {}
};
export const queryHTOrderListAction = async (params) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/query_order`, params)
return errcode !== 0 ? [] : result
}
export const queryOPIOrderAction = async (params) => {
const { errcode, result } = await fetchJSON(`${API_HOST}/getdvancedwlorder`, params)
return errcode !== 0 ? [] : result
};

@ -1,25 +0,0 @@
import { fetchJSON, postForm, postJSON } from '@/utils/request'
import { usingStorage } from '@/utils/usingStorage'
const WAI_SERVER_KEY = 'G-STR:WAI_SERVER'
const WAI_API_VER = '/api/v1'
export const postSendMsg = async (body) => {
const { waiServer } = usingStorage(WAI_SERVER_KEY)
// const { attaList = [], atta, content, ...bodyData } = body
// const formData = new FormData()
// Object.keys(bodyData).forEach(function (key) {
// formData.append(key, bodyData[key])
// })
// attaList.forEach(function (item) {
// formData.append('attachment', item)
// })
const { result } = await postJSON(`${waiServer}${WAI_API_VER}/messages/send`, body)
return result
}
export const fetchQRCode = (phone) => {
const { waiServer } = usingStorage(WAI_SERVER_KEY)
return fetchJSON(`${waiServer}${WAI_API_VER}/channels/qrcode`, { phone })
}

@ -1,6 +1,6 @@
.logo {
float: left;
height: 68px;
margin: 0 6px 0 0;
height: 36px;
margin: 16px 24px 16px 0;
background: rgba(255, 255, 255, 0.3);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M22 20V7L20 3H4L2 7.00353V20C2 20.5523 2.44772 21 3 21H21C21.5523 21 22 20.5523 22 20ZM4 9H20V19H4V9ZM5.236 5H18.764L19.764 7H4.237L5.236 5ZM15 11H9V13H15V11Z"></path></svg>

Before

Width:  |  Height:  |  Size: 262 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="32" height="32" fill="currentColor"><path d="M3 10H21V20.0044C21 20.5543 20.5551 21 20.0066 21H3.9934C3.44476 21 3 20.5552 3 20.0044V10ZM9 12V14H15V12H9ZM2 3.99981C2 3.44763 2.45531 3 2.9918 3H21.0082C21.556 3 22 3.44372 22 3.99981V8H2V3.99981Z"></path></svg>

Before

Width:  |  Height:  |  Size: 326 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="32" height="32" fill="currentColor"><path d="M3 10H2V4.00293C2 3.44903 2.45531 3 2.9918 3H21.0082C21.556 3 22 3.43788 22 4.00293V10H21V20.0015C21 20.553 20.5551 21 20.0066 21H3.9934C3.44476 21 3 20.5525 3 20.0015V10ZM19 10H5V19H19V10ZM4 5V8H20V5H4ZM9 12H15V14H9V12Z"></path></svg>

Before

Width:  |  Height:  |  Size: 347 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="32" height="32" fill="currentColor"><path d="M20.997 2.9918L20.9998 21.0082C20.9998 21.5447 20.5552 22 20.0066 22H3.9934C3.44495 22 3 21.556 3 21.0082V2.9918C3 2.45531 3.44468 2 3.99322 2H20.0036C20.5519 2 20.9969 2.44405 20.997 2.9918ZM9 13V9C9 8.44772 9.44772 8 10 8C10.5523 8 11 8.44772 11 9V13C11 13.5523 11.4477 14 12 14C12.5523 14 13 13.5523 13 13V9C13 7.34315 11.6569 6 10 6C8.34315 6 7 7.34315 7 9V13C7 15.7614 9.23858 18 12 18C14.7614 18 17 15.7614 17 13V8H15V13C15 14.6569 13.6569 16 12 16C10.3431 16 9 14.6569 9 13Z"></path></svg>

Before

Width:  |  Height:  |  Size: 608 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="32" height="32" fill="currentColor"><path d="M14 13.5V8C14 5.79086 12.2091 4 10 4C7.79086 4 6 5.79086 6 8V13.5C6 17.0899 8.91015 20 12.5 20C16.0899 20 19 17.0899 19 13.5V4H21V13.5C21 18.1944 17.1944 22 12.5 22C7.80558 22 4 18.1944 4 13.5V8C4 4.68629 6.68629 2 10 2C13.3137 2 16 4.68629 16 8V13.5C16 15.433 14.433 17 12.5 17C10.567 17 9 15.433 9 13.5V8H11V13.5C11 14.3284 11.6716 15 12.5 15C13.3284 15 14 14.3284 14 13.5Z"></path></svg>

Before

Width:  |  Height:  |  Size: 502 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M13.9999 18.9966H20.9999V20.9966H11.9999L8.00229 20.9991L1.51457 14.5113C1.12405 14.1208 1.12405 13.4877 1.51457 13.0971L12.1212 2.49053C12.5117 2.1 13.1449 2.1 13.5354 2.49053L21.3136 10.2687C21.7041 10.6592 21.7041 11.2924 21.3136 11.6829L13.9999 18.9966ZM15.6567 14.5113L19.1922 10.9758L12.8283 4.61185L9.29275 8.14738L15.6567 14.5113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 442 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M8.58564 8.85449L3.63589 13.8042L8.83021 18.9985L9.99985 18.9978V18.9966H11.1714L14.9496 15.2184L8.58564 8.85449ZM9.99985 7.44027L16.3638 13.8042L19.1922 10.9758L12.8283 4.61185L9.99985 7.44027ZM13.9999 18.9966H20.9999V20.9966H11.9999L8.00229 20.9991L1.51457 14.5113C1.12405 14.1208 1.12405 13.4877 1.51457 13.0971L12.1212 2.49053C12.5117 2.1 13.1449 2.1 13.5354 2.49053L21.3136 10.2687C21.7041 10.6592 21.7041 11.2924 21.3136 11.6829L13.9999 18.9966Z"></path></svg>

Before

Width:  |  Height:  |  Size: 555 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="32" height="32" fill="currentColor"><path d="M2 3H21.1384C21.4146 3 21.6385 3.22386 21.6385 3.5C21.6385 3.58701 21.6157 3.67252 21.5725 3.74807L18 10L21.5725 16.2519C21.7095 16.4917 21.6262 16.7971 21.3865 16.9341C21.3109 16.9773 21.2254 17 21.1384 17H4V22H2V3Z"></path></svg>

Before

Width:  |  Height:  |  Size: 343 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="32" height="32" fill="currentColor"><path d="M21.1384 3C21.4146 3 21.6385 3.22386 21.6385 3.5C21.6385 3.58701 21.6157 3.67252 21.5725 3.74807L18 10L21.5725 16.2519C21.7095 16.4917 21.6262 16.7971 21.3865 16.9341C21.3109 16.9773 21.2254 17 21.1384 17H4V22H2V3H21.1384ZM18.5536 5H4V15H18.5536L15.6965 10L18.5536 5Z"></path></svg>

Before

Width:  |  Height:  |  Size: 394 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12.6512 14.0654L11.6047 20H9.57389L10.9247 12.339L3.51465 4.92892L4.92886 3.51471L20.4852 19.0711L19.071 20.4853L12.6512 14.0654ZM11.7727 7.53009L12.0425 5.99999H10.2426L8.24257 3.99999H19.9999V5.99999H14.0733L13.4991 9.25652L11.7727 7.53009Z"></path></svg>

Before

Width:  |  Height:  |  Size: 347 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M5 3C4.5313 3 4.12549 3.32553 4.02381 3.78307L2.02381 12.7831C2.00799 12.8543 2 12.927 2 13V20C2 20.5523 2.44772 21 3 21H21C21.5523 21 22 20.5523 22 20V13C22 12.927 21.992 12.8543 21.9762 12.7831L19.9762 3.78307C19.8745 3.32553 19.4687 3 19 3H5ZM19.7534 12H15C15 13.6569 13.6569 15 12 15C10.3431 15 9 13.6569 9 12H4.24662L5.80217 5H18.1978L19.7534 12Z"></path></svg>

Before

Width:  |  Height:  |  Size: 455 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M4.02381 3.78307C4.12549 3.32553 4.5313 3 5 3H19C19.4687 3 19.8745 3.32553 19.9762 3.78307L21.9762 12.7831C21.992 12.8543 22 12.927 22 13V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V13C2 12.927 2.00799 12.8543 2.02381 12.7831L4.02381 3.78307ZM5.80217 5L4.24662 12H9C9 13.6569 10.3431 15 12 15C13.6569 15 15 13.6569 15 12H19.7534L18.1978 5H5.80217ZM16.584 14C15.8124 15.7659 14.0503 17 12 17C9.94968 17 8.1876 15.7659 7.41604 14H4V19H20V14H16.584Z"></path></svg>

Before

Width:  |  Height:  |  Size: 565 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M22 13.3414C21.3744 13.1203 20.7013 13 20 13C16.6863 13 14 15.6863 14 19C14 19.7013 14.1203 20.3744 14.3414 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H21C21.5523 3 22 3.44772 22 4V13.3414ZM12.0606 11.6829L5.64722 6.2377L4.35278 7.7623L12.0731 14.3171L19.6544 7.75616L18.3456 6.24384L12.0606 11.6829ZM21 18H24V20H21V23H19V20H16V18H19V15H21V18Z"></path></svg>

Before

Width:  |  Height:  |  Size: 460 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M22 13H20V7.23792L12.0718 14.338L4 7.21594V19H14V21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H21C21.5523 3 22 3.44772 22 4V13ZM4.51146 5L12.0619 11.662L19.501 5H4.51146ZM21 18H24V20H21V23H19V20H16V18H19V15H21V18Z"></path></svg>

Before

Width:  |  Height:  |  Size: 328 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M22 13.3414C21.3744 13.1203 20.7013 13 20 13C16.6863 13 14 15.6863 14 19C14 19.7013 14.1203 20.3744 14.3414 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H21C21.5523 3 22 3.44772 22 4V13.3414ZM12.0606 11.6829L5.64722 6.2377L4.35278 7.7623L12.0731 14.3171L19.6544 7.75616L18.3456 6.24384L12.0606 11.6829ZM19 22L15.4645 18.4645L16.8787 17.0503L19 19.1716L22.5355 15.636L23.9497 17.0503L19 22Z"></path></svg>

Before

Width:  |  Height:  |  Size: 504 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M22 14H20V7.23792L12.0718 14.338L4 7.21594V19H14V21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H21C21.5523 3 22 3.44772 22 4V14ZM4.51146 5L12.0619 11.662L19.501 5H4.51146ZM19 22L15.4645 18.4645L16.8787 17.0503L19 19.1716L22.5355 15.636L23.9497 17.0503L19 22Z"></path></svg>

Before

Width:  |  Height:  |  Size: 372 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M20 7.23792L12.0718 14.338L4 7.21594V19H13V21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H21C21.5523 3 22 3.44772 22 4V12H20V7.23792ZM19.501 5H4.51146L12.0619 11.662L19.501 5ZM20 18H23L19 22L15 18H18V14H20V18Z"></path></svg>

Before

Width:  |  Height:  |  Size: 323 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="32" height="32" fill="currentColor"><path d="M3 3H21C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3ZM20 7.23792L12.0718 14.338L4 7.21594V19H20V7.23792ZM4.51146 5L12.0619 11.662L19.501 5H4.51146Z"></path></svg>

Before

Width:  |  Height:  |  Size: 340 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="32" height="32" fill="currentColor"><path d="M2.24283 6.85435L11.4895 1.3086C11.8062 1.11865 12.2019 1.11872 12.5185 1.30878L21.7573 6.85433C21.9079 6.9447 22 7.10743 22 7.28303V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V7.28315C2 7.10748 2.09218 6.94471 2.24283 6.85435ZM4 8.13261V19H20V8.13214L12.0037 3.33237L4 8.13261ZM12.0597 13.6983L17.3556 9.23532L18.6444 10.7647L12.074 16.3017L5.36401 10.7717L6.63599 9.2283L12.0597 13.6983Z"></path></svg>

Before

Width:  |  Height:  |  Size: 531 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M2 5.5V3.9934C2 3.44476 2.45531 3 2.9918 3H21.0082C21.556 3 22 3.44495 22 3.9934V20.0066C22 20.5552 21.5447 21 21.0082 21H2.9918C2.44405 21 2 20.5551 2 20.0066V19H20V7.3L12 14.5L2 5.5ZM0 10H5V12H0V10ZM0 15H8V17H0V15Z"></path></svg>

Before

Width:  |  Height:  |  Size: 320 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M21 3C21.5523 3 22 3.44772 22 4V20.0066C22 20.5552 21.5447 21 21.0082 21H2.9918C2.44405 21 2 20.5551 2 20.0066V19H20V7.3L12 14.5L2 5.5V4C2 3.44772 2.44772 3 3 3H21ZM8 15V17H0V15H8ZM5 10V12H0V10H5ZM19.5659 5H4.43414L12 11.8093L19.5659 5Z"></path></svg>

Before

Width:  |  Height:  |  Size: 340 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M18.8032 8.4928C19.4663 8.81764 20.2118 9 21 9C21.3425 9 21.6769 8.96557 22 8.89998V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H16.1C16.0344 3.32311 16 3.65753 16 4C16 5.23672 16.449 6.36857 17.1929 7.24142L12.0606 11.6829L5.64722 6.2377L4.35278 7.7623L12.0731 14.3171L18.8032 8.4928ZM21 7C19.3431 7 18 5.65685 18 4C18 2.34315 19.3431 1 21 1C22.6569 1 24 2.34315 24 4C24 5.65685 22.6569 7 21 7Z"></path></svg>

Before

Width:  |  Height:  |  Size: 539 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M16.1 3C16.0344 3.32311 16 3.65753 16 4C16 4.34247 16.0344 4.67689 16.1 5H4.51146L12.0619 11.662L17.1098 7.14141C17.5363 7.66888 18.0679 8.10787 18.6728 8.42652L12.0718 14.338L4 7.21594V19H20V8.89998C20.3231 8.96557 20.6575 9 21 9C21.3425 9 21.6769 8.96557 22 8.89998V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H16.1ZM21 1C22.6569 1 24 2.34315 24 4C24 5.65685 22.6569 7 21 7C19.3431 7 18 5.65685 18 4C18 2.34315 19.3431 1 21 1Z"></path></svg>

Before

Width:  |  Height:  |  Size: 572 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M5 4.9967V7.9967H19V4.9967H5ZM4 2.9967H20C20.5523 2.9967 21 3.44442 21 3.9967V8.9967C21 9.54899 20.5523 9.9967 20 9.9967H4C3.44772 9.9967 3 9.54899 3 8.9967V3.9967C3 3.44442 3.44772 2.9967 4 2.9967ZM6 11.9967H12C12.5523 11.9967 13 12.4444 13 12.9967V15.9967H14V21.9967H10V15.9967H11V13.9967H5C4.44772 13.9967 4 13.549 4 12.9967V10.9967H6V11.9967ZM17.7322 13.7289L19.5 11.9612L21.2678 13.7289C22.2441 14.7052 22.2441 16.2882 21.2678 17.2645C20.2915 18.2408 18.7085 18.2408 17.7322 17.2645C16.7559 16.2882 16.7559 14.7052 17.7322 13.7289Z"></path></svg>

Before

Width:  |  Height:  |  Size: 640 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="32" height="32" fill="currentColor"><path d="M10.9042 2.10025L20.8037 3.51446L22.2179 13.414L13.0255 22.6063C12.635 22.9969 12.0019 22.9969 11.6113 22.6063L1.71184 12.7069C1.32131 12.3163 1.32131 11.6832 1.71184 11.2926L10.9042 2.10025ZM13.7327 10.5855C14.5137 11.3666 15.78 11.3666 16.5611 10.5855C17.3421 9.80448 17.3421 8.53815 16.5611 7.7571C15.78 6.97606 14.5137 6.97606 13.7327 7.7571C12.9516 8.53815 12.9516 9.80448 13.7327 10.5855Z"></path></svg>

Before

Width:  |  Height:  |  Size: 521 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save