chat.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. <template>
  2. <div id="chat">
  3. <van-row>
  4. <van-col span="24" class="main">
  5. <van-col span="24" class="one" :style="{ height: client.height - 87 + 'px' }">
  6. <template v-for="(i, index) in list">
  7. <template v-if="isSender(i, index)">
  8. <van-col span="24" class="senderTime" :key="`div${i.id}${index}`">
  9. <span :key="`senderTime${i.id}${index}`">[{{ i.send_time }}] {{ i.sender_name }}</span>
  10. <span v-if="i.type == '1'" v-html="i.content" :key="`senderContent${i.id}${index}`"></span>
  11. <span v-else-if="i.type == '2'">
  12. {{ getFile(i.file) }}<van-button type="info" size="mini" class="downBtn" @click="downFile(i.file)">下载</van-button>
  13. </span>
  14. </van-col>
  15. </template>
  16. <template v-else>
  17. <van-col span="24" class="receverTime" :key="`div${i.id}${index}`">
  18. <span :key="`receverTime${i.id}${index}`"> {{ i.sender_name }} [{{ i.send_time }}]</span>
  19. <span v-if="i.type == '1'" v-html="i.content" :key="`receverContent${i.id}${index}`"></span>
  20. <span v-else-if="i.type == '2'">
  21. {{ getFile(i.file) }}<van-button type="info" size="mini" class="downBtn" @click="downFile(i.file)">下载</van-button>
  22. </span>
  23. </van-col>
  24. </template>
  25. </template>
  26. </van-col>
  27. <van-col span="24" class="two">
  28. <van-col span="17" class="cont">
  29. <van-field v-model="content" placeholder="请输入内容" />
  30. </van-col>
  31. <van-col span="7" class="btn">
  32. <van-button type="info" size="small" @click="send">发送</van-button>
  33. <van-button type="info" size="small" @click="other">其它</van-button>
  34. </van-col>
  35. </van-col>
  36. </van-col>
  37. </van-row>
  38. <van-dialog v-model="show" class="dialog" title="文件" :showConfirmButton="false" :showCancelButton="false" :closeOnClickOverlay="false">
  39. <van-form>
  40. <van-field name="file" label="文件">
  41. <template #input>
  42. <van-uploader
  43. :fileList="fileForm.file"
  44. :max-count="1"
  45. :after-read="(file) => toUpload(file, 'file')"
  46. @delete="(file) => toDelete(file, 'file')"
  47. accept="file"
  48. />
  49. </template>
  50. </van-field>
  51. <div class="btn">
  52. <van-button type="danger" size="small" @click="twoClose">取消发送</van-button>
  53. <van-button type="info" size="small" @click="twoSend">提交发送</van-button>
  54. </div>
  55. </van-form>
  56. </van-dialog>
  57. </div>
  58. </template>
  59. <script>
  60. import { Toast } from 'vant';
  61. import { mapState, createNamespacedHelpers } from 'vuex';
  62. const { mapActions: upload } = createNamespacedHelpers('upload');
  63. const { mapActions: adminLogin } = createNamespacedHelpers('adminLogin');
  64. const { mapActions: patentchat } = createNamespacedHelpers('patentchat');
  65. const _ = require('lodash');
  66. export default {
  67. name: 'chat',
  68. props: {},
  69. components: {},
  70. data: function () {
  71. return {
  72. adminInfo: {},
  73. content: '',
  74. // 消息列表
  75. list: [],
  76. // 浏览器高度
  77. client: {},
  78. // 发送其他内容
  79. show: false,
  80. fileForm: {},
  81. };
  82. },
  83. created() {
  84. this.searchAdmin();
  85. this.search();
  86. },
  87. methods: {
  88. ...upload(['upload']),
  89. ...adminLogin({ adminQuery: 'query' }),
  90. ...patentchat(['create', 'query']),
  91. // 查询
  92. async search() {
  93. let res = await this.query({ id: this.user._id });
  94. if (this.$checkRes(res)) {
  95. this.$set(this, `list`, res.data);
  96. }
  97. },
  98. // 发言,正常内容
  99. async send() {
  100. if (this.content) {
  101. let arr = {
  102. type: '1',
  103. content: this.content,
  104. sender_id: this.user._id,
  105. sender_name: this.user.name,
  106. receiver_id: this.adminInfo._id,
  107. receiver_name: this.adminInfo.name,
  108. };
  109. let res = await this.create(arr);
  110. if (this.$checkRes(res)) {
  111. this.$toast({ type: `success`, message: `发言成功` });
  112. this.content = '';
  113. this.search();
  114. }
  115. } else {
  116. this.$toast({ type: `fail`, message: `缺少必要信息` });
  117. }
  118. },
  119. // 发言,发送文件
  120. other() {
  121. this.show = true;
  122. },
  123. // 提交发送
  124. async twoSend() {
  125. let data = this.fileForm;
  126. if (data.file) {
  127. let data = {
  128. type: '2',
  129. file: data.file,
  130. sender_id: this.user._id,
  131. sender_name: this.user.name,
  132. receiver_id: this.adminInfo._id,
  133. receiver_name: this.adminInfo.name,
  134. };
  135. let res = await this.create(data);
  136. if (this.$checkRes(res)) {
  137. this.$toast({ type: `success`, message: `发言成功` });
  138. this.fileForm = { file: [] };
  139. this.twoClose();
  140. this.search();
  141. }
  142. } else {
  143. this.$toast({ type: `fail`, message: `缺少必要信息` });
  144. }
  145. },
  146. // 取消发送
  147. twoClose() {
  148. this.show = false;
  149. },
  150. async toUpload({ file }, model) {
  151. // 上传,赋值
  152. const res = await this.upload({ file, dir: 'chat' });
  153. if (this.$checkRes(res)) {
  154. this.$set(this.fileForm, model, [{ name: res.name, url: res.uri }]);
  155. }
  156. },
  157. toDelete(file, model) {
  158. const index = this.fileForm[model].findIndex((f) => _.isEqual(f, file));
  159. this.fileForm[model].splice(index, 1);
  160. },
  161. // 处理文件
  162. getFile(data) {
  163. if (data.length > 0) {
  164. return data[0].name;
  165. }
  166. },
  167. // 下载文件
  168. downFile(data) {
  169. if (data.length > 0) {
  170. let url = data.map((i) => i.url);
  171. window.location.href = `${process.env.VUE_APP_HOST}/${url[0]}`;
  172. } else {
  173. this.$toast({ type: `fail`, message: `非正常文件,无法下载` });
  174. }
  175. },
  176. // 判断发言人
  177. isSender(data) {
  178. return this.user.id !== data.sender_id;
  179. },
  180. // 查询管理员
  181. async searchAdmin() {
  182. let res = await this.adminQuery({ code: 'JLKJQY' });
  183. if (this.$checkRes(res)) {
  184. this.$set(this, `adminInfo`, res.data[0]);
  185. }
  186. },
  187. },
  188. mounted() {
  189. let client = {
  190. height: document.documentElement.clientHeight || document.body.clientHeight,
  191. width: document.documentElement.clientWidth || document.body.clientWidth,
  192. };
  193. this.$set(this, `client`, client);
  194. },
  195. computed: {
  196. ...mapState(['user']),
  197. },
  198. metaInfo() {
  199. return { title: this.$route.meta.title };
  200. },
  201. watch: {
  202. test: {
  203. deep: true,
  204. immediate: true,
  205. handler(val) {},
  206. },
  207. },
  208. };
  209. </script>
  210. <style lang="less" scoped>
  211. .main {
  212. .one {
  213. overflow-x: hidden;
  214. overflow-y: auto;
  215. padding: 10px 5px;
  216. .senderTime {
  217. float: left;
  218. width: 100%;
  219. text-align: left;
  220. color: #666;
  221. font-size: 14px;
  222. margin: 0 0 5px 0;
  223. }
  224. .senderTime span:last-child {
  225. float: left;
  226. width: 100%;
  227. text-align: left;
  228. color: #000;
  229. }
  230. .receverTime {
  231. float: right;
  232. width: 100%;
  233. color: #666;
  234. font-size: 14px;
  235. margin: 0 0 5px 0;
  236. }
  237. .receverTime span:first-child {
  238. float: right;
  239. width: 100%;
  240. text-align: right;
  241. }
  242. .receverTime span:last-child {
  243. float: right;
  244. width: 100%;
  245. text-align: right;
  246. color: #000;
  247. }
  248. }
  249. .two {
  250. height: 40px;
  251. border-top: 1px solid #ccc;
  252. .cont {
  253. /deep/.van-cell {
  254. line-height: 20px;
  255. padding: 10px;
  256. }
  257. }
  258. .btn {
  259. text-align: center;
  260. /deep/.van-button--small {
  261. width: 54px;
  262. height: 40px;
  263. padding: 0;
  264. }
  265. }
  266. }
  267. }
  268. .dialog {
  269. .btn {
  270. text-align: center;
  271. .van-button {
  272. margin: 8px;
  273. }
  274. }
  275. }
  276. .downBtn {
  277. margin: 0 0 0 8px;
  278. /deep/.van-button__text {
  279. color: #ffffff !important;
  280. }
  281. }
  282. </style>