vue2 +富文本(wangeditor)

286 阅读1分钟

vue2 +富文本(wangeditor)

附件待完善

<template>
  <a-modal
    :width="1000"
    :visible="value"
    :title="'发送邮件'"
    :confirm-loading="loading"
    @cancel="handleCancel"
    @ok="handleSubmit"
  >
    <template slot="footer">
      <a-button @click="handleCancel"> 取消 </a-button>
      <a-button type="primary" :loading="btnLoading" @click="handleSubmit">
        发送
      </a-button>
    </template>
    <a-form
      class="g-form"
      :label-col="{ span: 3 }"
      :wrapper-col="{ span: 20 }"
      :form="formModal"
    >
      <a-row :gutter="[0, 0]" justify="center" align="middle">
        <a-col span="24">
          <a-form-item label="发件人:"
            ><label> {{ getSendName }} </label>
          </a-form-item>
        </a-col>
        <a-col span="24">
          <a-form-item required label="收件人:">
            <a-select
              :allowClear="true"
              mode="multiple"
              label-in-value
              :value="receiverList"
              placeholder="填写选择收件人"
              style="width: 100%"
              :filter-option="false"
              :not-found-content="notContent"
              @search="fetchUser"
              @change="(e, option) => handleChange(e, false, option)"
            >
              <a-spin v-if="fetching" slot="notFoundContent" size="small" />

              <a-select-option
                v-for="d in receiverData"
                :item="d"
                :label="d.name"
                :key="d.value"
              >
                {{ d.text }}
              </a-select-option>
            </a-select>
          </a-form-item>
        </a-col>
        <a-col span="24">
          <a-form-item label="已选择收件人:">
            <!-- <a-space> -->
            <a-tag color="#108ee9" :key="i" v-for="(v, i) in receiverList">
              {{ `${v.name}` }}
              <!-- <${v.email}> -->
            </a-tag>
            <!-- </a-space> -->
            <!-- <p class="bg-content">
              {{
                receiverList &&
                  receiverList.map(v => `${v.name}<${v.email}>`).join(',')
              }}
            </p> -->
          </a-form-item>
        </a-col>
        <a-col span="24">
          <a-form-item label="抄送:">
            <a-select
              :allowClear="true"
              mode="multiple"
              label-in-value
              :value="carbonCopyList"
              placeholder="填写选择抄送人"
              style="width: 100%"
              :filter-option="false"
              :not-found-content="notContent"
              @search="fetchUser"
              @change="(e, option) => handleChange(e, true, option)"
            >
              <a-spin v-if="fetching" slot="notFoundContent" size="small" />
              <a-select-option
                :item="d"
                v-for="d in receiverData"
                :label="d.name"
                :key="d.value"
              >
                {{ d.text }}
              </a-select-option>
            </a-select>
          </a-form-item>
        </a-col>
        <a-col span="24">
          <a-form-item label="已选择抄送人:">
            <a-tag color="#2db7f5" :key="i" v-for="(v, i) in carbonCopyList">
              {{ `${v.name}` }}
            </a-tag>
          </a-form-item>
        </a-col>
        <a-col span="24">
          <a-form-item label="主题:">
            <a-input
              allowClear
              autoComplete="off"
              @change="(e) => changeForm(e.target.value, 'topic')"
              v-decorator="[
                'topic',
                {
                  rules: [
                    {
                      required: true,
                      message: '必填',
                    },
                  ],
                  initialValue: detail.topic,
                },
              ]"
          /></a-form-item>
        </a-col>

        <!-- 富文本 -->
      </a-row>
      <a-row :gutter="[16, 16]">
        <a-col span="24">
          <a-form-item label="邮件内容:">
            <div style="border: 1px solid #ccc">
              <Toolbar
                style="border-bottom: 1px solid #ccc"
                :editor="editor"
                :defaultConfig="toolbarConfig"
                :mode="mode"
              />
              <Editor
                style="height: 300px; overflow-y: hidden; z-index: 999"
                v-model="html"
                :defaultConfig="editorConfig"
                :mode="mode"
                @onCreated="onCreated"
                @onChange="onChange"
                @onDestroyed="onDestroyed"
                @onMaxLength="onMaxLength"
                @onFocus="onFocus"
                @onBlur="onBlur"
                @customAlert="customAlert"
                @customPaste="customPaste"
              />
            </div>
          </a-form-item>
        </a-col>
        <a-col span="24">
          <a-form-item label="文件上传:">
            <a-button type="primary" @click="uploadFile"
              >上传excel文件</a-button
            >
          </a-form-item>
        </a-col>

        <a-col span="24">
          <a-form-item label="已上传文件:">
            <a
              style="margin-right: 16px"
              @click="downloadFile(v.url, v.title)"
              v-for="(v, i) in attachmentList"
              :key="i"
            >
              {{ v.title }}
            </a>
          </a-form-item>
        </a-col>
      </a-row>
    </a-form>

    <!-- 上传弹窗 -->
    <upload-modal
      v-if="isShow.upload"
      :from="'common'"
      :bizType="'2'"
      :name="'请上传excel文件'"
      :accept="'.xls,.xlsx'"
      :checkData="checkData"
      :isShow="isShow.upload"
      @cancel="uploadClose"
    />
  </a-modal>
</template>
<script>
import { mapState } from 'vuex'
import { PriceColumns, extraData } from './data'
import mixin from '@/views/mixin'
import { valuesTrim, timeShow, newGuid } from '@/utils'
import { costApi, commonApi, holidayApi, onLineEndApi } from '@/api'
import UploadModal from '@/views/components/uploader/upload-modal.vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { IToolbarConfig, createToolbar } from '@wangeditor/editor'
import debounce from 'lodash/debounce'
import { uniqWith, isEqual } from 'lodash'
export default {
  components: {
    UploadModal,
    Editor,
    Toolbar,
  },
  mixins: [mixin],
  computed: {
    ...mapState('dictionary', [
      'GeneralChooseType',
      'ClaimPreserveFieldSource',
    ]),
    ...mapState('user', ['userInfo']),
    notContent() {
      return this.fetching ? undefined : null
    },
    getSendName() {
      let { name, uid } = this.userInfo
      return `${name}(${uid})<quotation@ztn.com>`
    },
  },
  props: {
    value: {
      type: Boolean,
      default: false,
    },

    type: String,
    checkRow: {
      type: Object,
      default: () => {
        return {}
      },
    },
    selectRows: {
      type: Array,
      default: () => {
        return []
      },
    },
  },
  data() {
    this.lastFetchId = 0
    this.fetchUser = debounce(this.fetchUser, 800)
    return {
      carbonCopyData: [],
      carbonCopyList: [],
      receiverData: [],
      receiverList: [],
      fetching: false,
      isEditor: false,
      editor: null,
      isReset: false,
      html: '<p></p>',
      toolbarConfig: {},
      editorConfig: { placeholder: '请输入内容...' },
      mode: 'default', // or 'simple'
      checkData: {},
      isShow: {
        upload: false,
      },
      channelList: [],
      dictArr: [],
      detail: this.checkRow,
      channelSource,
      columns: PriceColumns,
      formModal: this.$form.createForm(this, { name: 'priceModal' }),
      resetKey: false,
      loading: false,
      btnLoading: false,
      dataSource: [],
      CountryList: [],
      attachmentList: [],
      allSearchList: [],
    }
  },

  created() {
    this.initEditConfig()
    if (this.selectRows.length) {
      this.getConfig()
    }
  },
  mounted() {
    this.$nextTick(() => {})
  },
  beforeDestroy() {
    const editor = this.editor
    if (editor == null) return
    editor.destroy() // 组件销毁时,及时销毁编辑器
  },
  methods: {
    getDictName,
    newGuid,

    packageArr(arr) {
      console.log(arr, 123)

      return arr.map((user, i) => {
        return {
          key: user.employeeCode,
          label: `${user.name}<${user.email}>`,
          text: `${user.name}<${user.email}>`,
          value: user.employeeCode,
          employeeCode: user.employeeCode,
          name: user.name,
          email: user.email,
        }
      })
    },
    getConfig() {
      onLineEndApi
        .onlineEmailDetail({ idList: this.selectRows.map((v) => v.id) })
        .then((res) => {
          console.log(res)
          this.quotationIdList = res.data.quotationIdList
          this.attachmentList = res.data.attachmentList || []
          // 已选择的
          this.carbonCopyList = this.packageArr(res.data.carbonCopyList || [])
          this.receiverList = this.packageArr(res.data.receiverList || [])
          console.log(this.carbonCopyList, this.receiverList, 222)
          const arr = uniqWith(
            this.carbonCopyList.concat(this.receiverList),
            isEqual
          )
          console.log(arr, 444)
          this.allSearchList = this.packageArr(arr || [])
          this.receiverData = this.packageArr(arr || [])

          console.log(222, this.allSearchList, this.receiverData)
          this.detail.topic = res.data.topic || ''
          this.html = `<p>${res.data.content || ''}</p>`
          // this.isReset = true
        })
        .catch((err) => {})
    },
    handleChange(value, isCarbonCopy, option) {
      console.log(value, option, this.allSearchList)
      let receiverData = []

      value.map((v, i) => {
        const target = this.allSearchList.find((m) => v.key === m.value) // key: "test003" value: "test003
        if (target) {
          const { name, email, employeeCode } = target
          receiverData.push({
            ...v,
            name: name,
            email: email,
            employeeCode: employeeCode,
          })
        }
      })
      console.log(receiverData, 111)

      if (isCarbonCopy) {
        Object.assign(this, {
          carbonCopyList: receiverData,
          // receiverData: [],
          fetching: false,
        })
      } else {
        Object.assign(this, {
          receiverList: receiverData,
          // receiverData: [],
          fetching: false,
        })
      }

      console.log(this.receiverList, this.carbonCopyList)
    },
    fetchUser(value) {
      let params = { current: 1, fuzzy: value, size: 999 }
      this.lastFetchId += 1
      const fetchId = this.lastFetchId
      this.data = []
      this.fetching = true
      onLineEndApi
        .employeePage(params)
        .then((res) => {
          console.log(res, 11)
          if (fetchId !== this.lastFetchId) {
            return
          }
          const data =
            (res &&
              res.data &&
              res.data.records.map((user) => ({
                text: `${user.employeeName}<${user.email}>`,
                value: user.employeeCode,
                employeeCode: user.employeeCode,
                name: user.employeeName,
                email: user.email,
              }))) ||
            []

          this.receiverData = data
          this.allSearchList = this.allSearchList.concat(this.receiverData)
          this.fetching = false
          console.log(this.receiverData, 11)
        })
        .catch((err) => {
          this.fetching = false
        })
    },
    initEditConfig() {
      const editorConfig = { MENU_CONF: {} }
      editorConfig.placeholder = '请输入内容...'
      editorConfig.MENU_CONF['uploadImage'] = {
        allowedFileTypes: ['image/*'],
        onBeforeUpload(file) {
          return file
        },
        onProgress(progress) {
          console.log('progress', progress)
        },
        onSuccess(file, res) {
          console.log(`${file.name} 上传成功`, res)
        },
        onFailed(file, res) {
          console.log(`${file.name} 上传失败`, res)
        },
        onError(file, err, res) {
          console.log(`${file.name} 上传出错`, err, res)
        },

        async customUpload(file, insertFn) {
          const formData = new FormData()
          formData.append('file', file)
          formData.append('bizType', '3')
          const { code, data, Message } = await commonApi.commonUpload(formData)
          insertFn(data, file.name, data)
        },
      }
      this.editorConfig = editorConfig
    },
    onCreated(editor) {
      this.editor = Object.seal(editor)
      console.log('onCreated', editor)
    },
    onChange(editor) {
      console.log('onChange', editor.getHtml()) // onChange 时获取编辑器最新内容
      this.content = editor.getHtml()
    },
    insertTextHandler() {
      const editor = this.editor
      if (editor == null) return
      editor.insertText('')
    },
    printEditorHtml() {
      const editor = this.editor
      if (editor == null) return
      console.log(editor.getHtml())
    },
    disableHandler() {
      const editor = this.editor
      if (editor == null) return
      editor.disable()
    },

    onDestroyed(editor) {
      console.log('onDestroyed', editor)
    },
    onMaxLength(editor) {
      console.log('onMaxLength', editor)
    },
    onFocus(editor) {
      console.log('onFocus', editor)
    },
    onBlur(editor) {
      console.log('onBlur', editor)
    },
    customAlert(info, type) {
      // window.alert(`customAlert in Vue demo\n${type}:\n${info}`)
    },
    customPaste(editor, event, callback) {
      // editor.insertText('xxx')
      // event.preventDefault()
      // callback(false) // 返回值(注意,vue 事件的返回值,不能用 return)
      return true
    },

    uploadClose(flag, data) {
      if (data) {
        const { fileName, fileUrl } = data
        this.attachmentList.push({ title: fileName, url: fileUrl })
      }
      this.isShow.upload = false
    },
    // 上传文件 弹窗
    uploadFile() {
      this.isShow.upload = true
    },
    changeForm(e, field) {
      this.detail[field] = e
    },
    //提交
    handleSubmit() {
      if (!this.receiverList.length) {
        return this.$message.warn('请填写选择收件人')
      }
      this.formModal.validateFields((error, values) => {
        if (error) {
          return
        }
        if (this.editor.isEmpty()) {
          return this.$message.warn('请填写富文本内容')
        }
        valuesTrim(values)
        const { topic } = this.detail
        let params = {
          quotationIdList: this.selectRows.length
            ? this.quotationIdList
            : undefined,
          attachmentList: this.attachmentList,
          carbonCopyList: this.carbonCopyList, // email  name
          content: this.content,
          receiverList: this.receiverList, // email  name
          senderEmail: this.userInfo.uid,
          senderName: `${this.userInfo.name}<${this.userInfo.uid}>`,
          topic,
        }
        this.btnLoading = true
        onLineEndApi
          .emailSend(params)
          .then((res) => {
            this.btnLoading = false
            this.$message.success('邮件发送成功')
            this.$emit('cancel', true)
          })
          .catch((err) => {
            this.btnLoading = false
            this.$message.error(err.Message || '邮件发送失败')
          })
      })
    },
    handleCancel() {
      this.$emit('cancel')
    },
  },
}
</script>
<style src="@wangeditor/editor/dist/css/style.css"></style>
<style lang="less">
.w-e-modal {
  width: 400px !important;
  padding-top: 32px;
  .babel-container {
    display: flex;
    margin-bottom: 8px;
    span {
      // width: 200px;
      padding: 0 8px;
      margin: 0;
    }
    input {
      flex: 1;
      padding: 0 11px;
    }
  }
  .button-container {
    text-align: right;
    button {
      height: auto;
      padding: 4px 16px;
    }
  }
}
</style>