index.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. <template>
  2. <div class="action-container">
  3. <div class="action-list">
  4. <el-popover
  5. v-for="(item, index) in getOptions"
  6. :key="index"
  7. placement="top"
  8. trigger="hover"
  9. :content="item.content"
  10. popper-class="custom-popper"
  11. :close-delay="10"
  12. >
  13. <el-upload
  14. v-if="item.type == 'image'"
  15. :disabled="disabled"
  16. action="#"
  17. accept=".jpg,.png,.svg,.jpeg,.gif,.bmp"
  18. :file-list="imageList"
  19. :http-request="uploadImage"
  20. :show-file-list="false"
  21. :multiple="true"
  22. :before-upload="beforeUploadImage"
  23. slot="reference"
  24. class="mr16"
  25. >
  26. <span class="action-img image" @click="checkLogin"></span>
  27. </el-upload>
  28. <el-upload
  29. class="mr16"
  30. v-else-if="item.type == 'attach'"
  31. :disabled="disabled"
  32. action="#"
  33. accept=".pdf,.word,.docx,.ppt,.pptx"
  34. :file-list="attachList"
  35. :http-request="uploadFiles"
  36. :show-file-list="false"
  37. :multiple="true"
  38. :before-upload="beforeUploadAttach"
  39. slot="reference"
  40. >
  41. <span class="action-img attach" @click="checkLogin"></span>
  42. </el-upload>
  43. <div v-else-if="item.type == 'rate'" slot="reference">
  44. <span v-show="isRobot === 2" class="action-img rate mr16" :class="item.type" @click="onClick(item.type)"></span>
  45. </div>
  46. </el-popover>
  47. </div>
  48. <div v-if="isLink && form !== 'aside'" class="action-customer-container">
  49. <slot></slot>
  50. <div class="action-customer-item turn-btn" @click.stop="onTurn('转人工')">转人工</div>
  51. <div class="action-customer-item" v-for="(item, index) in btn" :key="index" @click.stop="onTurn(item)">{{item}}</div>
  52. <slot></slot>
  53. </div>
  54. </div>
  55. </template>
  56. <script>
  57. import { Popover, Upload } from 'element-ui'
  58. import { fileUpload } from '@/api/modules/'
  59. import {mapGetters} from "vuex";
  60. export default {
  61. name: 'action-container',
  62. components: {
  63. [Popover.name]: Popover,
  64. [Upload.name]: Upload
  65. },
  66. props: {
  67. /**
  68. * 支持的配置['keyboard', 'sound', 'image', 'attach', 'rate']
  69. * 键盘:keyboard
  70. * 语音:sound
  71. * 图片:image
  72. * 附件:attach
  73. * 评分:rate
  74. */
  75. options: {
  76. type: Array,
  77. default: () => {
  78. return ['image']
  79. }
  80. },
  81. /**
  82. * 右侧人工跳转
  83. */
  84. isLink: {
  85. type: Boolean,
  86. default: false
  87. },
  88. isRobot: {
  89. type: Number,
  90. default: 0
  91. },
  92. btn:{
  93. type: Array,
  94. default: () => {
  95. return []
  96. }
  97. }
  98. },
  99. data () {
  100. return {
  101. list: this.options,
  102. imageList: [],
  103. attachList: [],
  104. disabled: false
  105. }
  106. },
  107. watch: {
  108. options (val) {
  109. this.list = val
  110. }
  111. },
  112. computed: {
  113. ...mapGetters('user', ['isLogin']),
  114. getOptions () {
  115. const list = this.list
  116. const arr = list.map(v => {
  117. const temp = {}
  118. switch (v) {
  119. case 'keyboard':
  120. temp.type = 'keyboard'
  121. temp.content = '键盘'
  122. break
  123. case 'sound':
  124. temp.type = 'sound'
  125. temp.content = '语音'
  126. break
  127. case 'image':
  128. temp.type = 'image'
  129. temp.content = '图片'
  130. break
  131. case 'attach':
  132. temp.type = 'attach'
  133. temp.content = '文件'
  134. break
  135. case 'rate':
  136. temp.type = 'rate'
  137. temp.content = '评价客服'
  138. break
  139. }
  140. return temp
  141. })
  142. return arr
  143. }
  144. },
  145. created() {
  146. // 是否是iframe侧边栏打开的
  147. this.form = this.$route.query.from
  148. },
  149. methods: {
  150. onClick (data) {
  151. this.$emit('action', data)
  152. },
  153. onTurn (data) {
  154. this.$emit('turn', data)
  155. },
  156. async uploadImage (file) {
  157. // this.$emit('upload-image', file.file)
  158. const params = new FormData()
  159. params.append('file', file.file)
  160. const { data } = await fileUpload(params)
  161. if (data) {
  162. this.imageList.push(data)
  163. this.$emit('upload-image', data)
  164. }
  165. },
  166. async uploadFiles (file) {
  167. const params = new FormData()
  168. params.append('file', file.file)
  169. const { data } = await fileUpload(params)
  170. if (data) {
  171. this.attachList.push(data)
  172. this.$emit('upload-attach', data)
  173. }
  174. },
  175. beforeUploadImage (file) {
  176. const size = file.size / 1024 / 1024
  177. const fileSuffix = file.name.substring(file.name.lastIndexOf('.') + 1)
  178. const whiteList = ['jpg', 'jpeg', 'png', 'svg', 'gif', 'bmp']
  179. if (size > 10) {
  180. this.$toast('上传失败,文件大小不能超过10M')
  181. return false
  182. }
  183. if (whiteList.indexOf(fileSuffix) === -1) {
  184. this.$toast('上传失败,只能选择图片格式')
  185. return false
  186. }
  187. },
  188. beforeUploadAttach (file) {
  189. const size = file.size / 1024 / 1024
  190. const fileSuffix = file.name.substring(file.name.lastIndexOf('.') + 1)
  191. const whiteList = ['doc', 'docx', 'pdf', 'ppt', 'pptx']
  192. if (size > 10) {
  193. this.$toast('上传失败,文件大小不能超过10M')
  194. return false
  195. }
  196. if (whiteList.indexOf(fileSuffix) === -1) {
  197. this.$toast('上传失败,只能选择PDF、WORD、PPT格式')
  198. return false
  199. }
  200. },
  201. checkLogin () {
  202. if (!this.isLogin) {
  203. this.disabled = true
  204. this.$emit('close')
  205. this.$showLoginDialog()
  206. }
  207. }
  208. }
  209. }
  210. </script>
  211. <style lang="scss">
  212. .custom-popper{
  213. min-width: 0!important;
  214. padding: 8px 16px!important;
  215. }
  216. </style>
  217. <style lang="scss" scoped>
  218. .action-container{
  219. position: relative;
  220. width: 100%;
  221. height: 48px;
  222. display: flex;
  223. justify-content: space-between;
  224. padding: 8px 0 16px;
  225. box-sizing: border-box;
  226. &::after{
  227. content: '';
  228. position: absolute;
  229. top: 0;
  230. width: calc(100% + 64px);
  231. height: 1px;
  232. background: #DADADA;
  233. left: -32px;
  234. right: -32px;
  235. z-index: 99;
  236. }
  237. .action-list{
  238. display: flex;
  239. align-items: center;
  240. }
  241. &.white{
  242. background: #fff;
  243. }
  244. .action-img{
  245. display: inline-block;
  246. width: 24px;
  247. height: 24px;
  248. //margin-right: 16px;
  249. background-repeat: no-repeat;
  250. background-position: center;
  251. background-size: contain;
  252. cursor: pointer;
  253. &.keyboard{
  254. background-image: url('~@/assets/image/keyboard.png');
  255. }
  256. &.sound{
  257. background-image: url('~@/assets/image/sound.png');
  258. }
  259. &.image{
  260. background-image: url('~@/assets/image/image.png');
  261. }
  262. &.attach{
  263. background-image: url('~@/assets/image/attach.png');
  264. }
  265. &.rate{
  266. background-image: url('~@/assets/image/rate.png');
  267. }
  268. }
  269. .mr16{
  270. margin-right: 16px;
  271. }
  272. .image:hover{
  273. background-image: url('~@/assets/image/image_h.png');
  274. }
  275. .rate:hover{
  276. background-image: url('~@/assets/image/rate_h.png');
  277. }
  278. .action-customer-container{
  279. display: flex;
  280. align-items: center;
  281. }
  282. .action-customer-item{
  283. padding: 3px 9px;
  284. margin-right: 8px;
  285. font-size: 12px;
  286. line-height: 18px;
  287. border-radius: 4px;
  288. border: 1px solid #E0E0E0;
  289. background: #fff;
  290. color: #686868;
  291. cursor: pointer;
  292. }
  293. .turn-btn{
  294. padding-left: 44px;
  295. background: url('~@/assets/image/hand-gray.png') no-repeat 8px center #fff;
  296. background-size: 18px 18px;
  297. cursor: pointer;
  298. }
  299. }
  300. ::v-deep {
  301. .el-upload {
  302. width: 23px;
  303. height: 23px;
  304. }
  305. }
  306. </style>