mailWrite.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. <template>
  2. <div v-loading="loading" style="padding: 10px">
  3. <div style="margin-bottom: 10px; padding-left: 65px">
  4. <el-button type="primary" @click="handleSend">发送</el-button>
  5. </div>
  6. <div style="width: 100%">
  7. <byForm
  8. :formConfig="formConfig"
  9. :formOption="formOption"
  10. v-model="formData.data"
  11. :rules="rules"
  12. ref="submit"
  13. >
  14. <template #to>
  15. <div>
  16. <div style="display: flex">
  17. <el-autocomplete
  18. v-model="formData.data.to"
  19. clearable
  20. class="inline-input w-50"
  21. placeholder="请输入"
  22. @select="handlePerson"
  23. :fetch-suggestions="querySearchPerson"
  24. >
  25. </el-autocomplete>
  26. <el-button
  27. type="primary"
  28. @click="handleAdd(10)"
  29. style="margin-left: 10px"
  30. :disabled="!formData.data.to"
  31. >添加</el-button
  32. >
  33. </div>
  34. <div style="margin-top: 15px">
  35. <el-tag
  36. style="margin-right: 10px"
  37. class="ml-2"
  38. type="info"
  39. v-for="(item, index) in to"
  40. :key="index"
  41. closable
  42. @close="handleClose(index, 10)"
  43. >{{ item.address }}</el-tag
  44. >
  45. </div>
  46. </div>
  47. </template>
  48. <template #cc>
  49. <div>
  50. <div style="display: flex">
  51. <el-autocomplete
  52. v-model="formData.data.cc"
  53. clearable
  54. class="inline-input w-50"
  55. placeholder="请输入"
  56. @select="handlePerson"
  57. :fetch-suggestions="querySearchPerson"
  58. >
  59. </el-autocomplete>
  60. <el-button
  61. type="primary"
  62. @click="handleAdd(20)"
  63. style="margin-left: 10px"
  64. :disabled="!formData.data.cc"
  65. >添加</el-button
  66. >
  67. </div>
  68. <div style="margin-top: 15px">
  69. <el-tag
  70. style="margin-right: 10px"
  71. class="ml-2"
  72. type="info"
  73. v-for="(item, index) in cc"
  74. :key="index"
  75. closable
  76. @close="handleClose(index, 20)"
  77. >{{ item.address }}</el-tag
  78. >
  79. </div>
  80. </div>
  81. </template>
  82. <template #bcc>
  83. <div>
  84. <div style="display: flex">
  85. <el-autocomplete
  86. v-model="formData.data.bcc"
  87. clearable
  88. class="inline-input w-50"
  89. placeholder="请输入"
  90. @select="handlePerson"
  91. :fetch-suggestions="querySearchPerson"
  92. >
  93. </el-autocomplete>
  94. <el-button
  95. type="primary"
  96. @click="handleAdd(30)"
  97. style="margin-left: 10px"
  98. :disabled="!formData.data.bcc"
  99. >添加</el-button
  100. >
  101. </div>
  102. <div style="margin-top: 15px">
  103. <el-tag
  104. style="margin-right: 10px"
  105. class="ml-2"
  106. type="info"
  107. v-for="(item, index) in bcc"
  108. :key="index"
  109. closable
  110. @close="handleClose(index, 30)"
  111. >{{ item.address }}</el-tag
  112. >
  113. </div>
  114. </div>
  115. </template>
  116. <template #contentSlot>
  117. <div style="width: 100%">
  118. <Editor
  119. :value="formData.data.content"
  120. @updateValue="updateContent"
  121. />
  122. </div>
  123. </template>
  124. <template #fileSlot>
  125. <div style="width: 100%">
  126. <el-upload
  127. v-model:fileList="fileList"
  128. class="upload-demo"
  129. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  130. :data="uploadData"
  131. drag
  132. multiple
  133. :show-file-list="false"
  134. :before-upload="handleBeforeUpload"
  135. >
  136. <div>
  137. <img
  138. src="@/assets/images/icon_attachment.svg"
  139. class="att-img"
  140. fit="scale-down"
  141. />
  142. <span style="padding-left: 8px"
  143. >将文件拖到此处,或<span style="color: #409eff"
  144. >点击上传</span
  145. ></span
  146. >
  147. </div>
  148. </el-upload>
  149. <div class="att-box">
  150. <div v-for="(itemFile, index) in fileListCopy" :key="index">
  151. <div class="att-item">
  152. <img
  153. src="@/assets/images/icon_dz.svg"
  154. style="cursor: pointer"
  155. fit="scale-down"
  156. />
  157. <div class="att-name">
  158. {{ itemFile.fileName }}
  159. </div>
  160. <img
  161. src="@/assets/images/icon_delete.svg"
  162. class="att-img"
  163. fit="scale-down"
  164. />
  165. </div>
  166. </div>
  167. </div>
  168. </div>
  169. </template>
  170. </byForm>
  171. </div>
  172. </div>
  173. </template>
  174. <script setup>
  175. import byForm from "@/components/byForm/index";
  176. import { ElMessage, ElMessageBox } from "element-plus";
  177. import Editor from "@/components/Editor/index.vue";
  178. import { validEmail } from "@/utils/validate.js";
  179. import useMailStore from "@/store/modules/mail";
  180. const mailStore = useMailStore();
  181. console.log(mailStore, "wda");
  182. const { proxy } = getCurrentInstance();
  183. const loading = ref(false);
  184. let uploadData = ref({});
  185. const fileList = ref([]);
  186. const fileListCopy = ref([]);
  187. const formOption = reactive({
  188. inline: true,
  189. labelWidth: 65,
  190. itemWidth: 100,
  191. labelPosition: "right",
  192. });
  193. const formConfig = computed(() => {
  194. return [
  195. {
  196. type: "slot",
  197. slotName: "to",
  198. label: "收件人",
  199. prop: "to",
  200. },
  201. {
  202. type: "slot",
  203. slotName: "cc",
  204. label: "抄送人",
  205. prop: "cc",
  206. },
  207. {
  208. type: "slot",
  209. slotName: "bcc",
  210. label: "密送人",
  211. prop: "bcc",
  212. },
  213. {
  214. type: "input",
  215. prop: "subject",
  216. label: "主题",
  217. required: true,
  218. itemWidth: 50.1,
  219. itemType: "text",
  220. },
  221. {
  222. type: "slot",
  223. slotName: "fileSlot",
  224. label: "附件",
  225. },
  226. {
  227. type: "slot",
  228. slotName: "contentSlot",
  229. label: "正文",
  230. },
  231. {
  232. type: "input",
  233. prop: "replyTo",
  234. label: "发件人",
  235. required: true,
  236. itemWidth: 50,
  237. itemType: "text",
  238. },
  239. ];
  240. });
  241. const rules = ref({
  242. subject: [{ required: true, message: "请输入主题", trigger: "blur" }],
  243. replyTo: [{ required: true, message: "请输入发件人", trigger: "blur" }],
  244. });
  245. const formData = reactive({
  246. data: {
  247. content: "",
  248. },
  249. });
  250. const to = ref([]);
  251. const cc = ref([]);
  252. const bcc = ref([]);
  253. const replyTo = ref([]);
  254. const submit = ref(null);
  255. const handleSend = () => {
  256. submit.value.handleSubmit(() => {
  257. const data = { ...formData.data };
  258. if (!to.value.length > 0) {
  259. return ElMessage({
  260. message: "请添加收件人",
  261. type: "info",
  262. });
  263. }
  264. if (data.content) {
  265. let replyTo = [
  266. {
  267. address: formData.data.replyTo,
  268. personal: null,
  269. },
  270. ];
  271. const submitData = {
  272. type: mailStore.selectMail.type,
  273. mailboxId: mailStore.selectMail.id,
  274. subject: data.subject,
  275. content: data.content,
  276. to: to.value,
  277. cc: cc.value,
  278. bcc: bcc.value,
  279. replyTo: replyTo,
  280. fileList: fileListCopy.value.map((x) => ({
  281. fileName: x.fileName,
  282. fileUrl: x.fileUrl,
  283. })),
  284. };
  285. proxy.post("/mailService/sendMail", submitData).then((res) => {
  286. console.log(res, "aa");
  287. });
  288. } else {
  289. return ElMessage({
  290. message: "请输入正文",
  291. type: "info",
  292. });
  293. }
  294. });
  295. };
  296. const updateContent = (val) => {
  297. formData.data.content = val;
  298. };
  299. const handleBeforeUpload = async (file) => {
  300. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  301. uploadData.value = res.uploadBody;
  302. fileListCopy.value.push({
  303. id: res.id,
  304. fileName: res.fileName,
  305. path: res.fileUrl,
  306. fileUrl: res.fileUrl,
  307. uid: file.uid,
  308. });
  309. };
  310. const handleClose = (index, val) => {
  311. switch (val) {
  312. case 10:
  313. to.value.splice(index, 1);
  314. break;
  315. case 20:
  316. cc.value.splice(index, 1);
  317. break;
  318. case 30:
  319. bcc.value.splice(index, 1);
  320. break;
  321. }
  322. };
  323. const handleAdd = (val) => {
  324. switch (val) {
  325. case 10: {
  326. if (!validEmail(formData.data.to))
  327. return ElMessage({
  328. message: "邮箱格式不正确",
  329. type: "info",
  330. });
  331. to.value.push({
  332. address: formData.data.to,
  333. personal: null,
  334. });
  335. console.log(to.value, "ada");
  336. formData.data.to = "";
  337. break;
  338. }
  339. case 20: {
  340. if (!validEmail(formData.data.cc))
  341. return ElMessage({
  342. message: "邮箱格式不正确",
  343. type: "info",
  344. });
  345. cc.value.push({
  346. address: formData.data.cc,
  347. personal: null,
  348. });
  349. formData.data.cc = "";
  350. break;
  351. }
  352. case 30: {
  353. if (!validEmail(formData.data.bcc))
  354. return ElMessage({
  355. message: "邮箱格式不正确",
  356. type: "info",
  357. });
  358. bcc.value.push({
  359. address: formData.data.bcc,
  360. personal: null,
  361. });
  362. formData.data.bcc = "";
  363. break;
  364. }
  365. }
  366. };
  367. const handlePerson = () => {};
  368. const createFilter = (queryString) => {
  369. return (restaurant) => {
  370. return (
  371. restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
  372. );
  373. };
  374. };
  375. const distributionCenterData = ref([]);
  376. const querySearchPerson = (queryString, callback) => {
  377. const results = queryString
  378. ? distributionCenterData.value.filter(createFilter(queryString))
  379. : distributionCenterData.value;
  380. callback(results);
  381. };
  382. </script>
  383. <style lang="scss" scoped>
  384. .att-img {
  385. height: 18px;
  386. width: 18px;
  387. transform: translateY(4px);
  388. }
  389. .att-box {
  390. padding-bottom: 8px;
  391. display: flex;
  392. flex-wrap: wrap;
  393. margin-top: 10px;
  394. .att-item {
  395. width: 200px;
  396. background-color: #eeeeee;
  397. height: 28px;
  398. line-height: 26px;
  399. margin-right: 16px;
  400. padding-left: 8px;
  401. display: flex;
  402. margin-bottom: 8px;
  403. }
  404. .att-name {
  405. padding-left: 8px;
  406. width: 150px;
  407. white-space: nowrap;
  408. overflow: hidden;
  409. text-overflow: ellipsis;
  410. cursor: pointer;
  411. }
  412. }
  413. :deep(.el-upload-dragger) {
  414. width: 250px;
  415. height: 40px;
  416. line-height: 40px;
  417. padding: 0 8px;
  418. }
  419. </style>