message.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. <template>
  2. <div :data-id="info.id">
  3. <!--文本、任务、报告、视频通话-->
  4. <div v-if="info.type==='text' || info.type==='taskB' || info.type==='report' || info.type==='video' || info.type==='voice'">
  5. <div v-if="info.self===true" class="list-right">
  6. <div v-if="info.error" class="item-error" @click="clickError(info.error)">
  7. <Icon type="md-alert" />
  8. </div>
  9. <div class="item-right">
  10. <div class="item-username" @click="clickUser">
  11. <em class="item-name"><user-view :username="userName" :info="info" placement="left"/></em>
  12. <em v-if="info.indate" class="item-date">{{formatCDate(info.indate)}}</em>
  13. </div>
  14. <div class="item-text" :class="{'text-emoji':textIsEmoji(info.text), 'text-error':info.error}">
  15. <div class="item-text-view">{{textMsg(info.text)}}</div>
  16. </div>
  17. <template v-if="info.type==='taskB'">
  18. <div v-if="info.other.type==='task'" class="item-link" @click="taskDetail(info.other.id)"><span>{{$L('来自关注任务')}}:</span><a href="javascript:void(0)">{{info.other.title}}</a></div>
  19. <div v-if="info.other.type==='file'" class="item-link"><span>{{$L('来自关注任务')}}:</span><a target="_blank" :href="fileDownUrl(info.other.id)">{{info.other.name}}</a></div>
  20. </template>
  21. <div v-else-if="info.type==='report'" class="item-link" @click="reportDetail(info.other.id, info.other.title)"><span>{{$L('来自工作报告')}}:</span><a href="javascript:void(0)">{{info.other.title}}</a></div>
  22. <div v-else-if="info.type==='video' || info.type==='voice'" class="item-link">
  23. <Icon v-if="info.type==='voice'" type="ios-call-outline"/>
  24. <Icon v-else type="ios-videocam-outline"/>
  25. <span>{{$L('通话时长:%', formatSecond(info.other.second))}}</span>
  26. </div>
  27. </div>
  28. <UserImg :info="info" @click="clickUser" class="item-userimg"/>
  29. </div>
  30. <div v-else-if="info.self===false" class="list-item">
  31. <UserImg :info="info" @click="clickUser" class="item-userimg"/>
  32. <div class="item-left">
  33. <div class="item-username" @click="clickUser">
  34. <em class="item-name"><user-view :username="userName" :info="info" placement="right"/></em>
  35. <em v-if="info.__usertag" class="item-tag">{{info.__usertag}}</em>
  36. <em v-if="info.indate" class="item-date">{{formatCDate(info.indate)}}</em>
  37. </div>
  38. <div class="item-text" :class="{'text-emoji':textIsEmoji(info.text), 'text-error':info.error}">
  39. <div class="item-text-view">{{textMsg(info.text)}}</div>
  40. </div>
  41. <template v-if="info.type==='taskB'">
  42. <div v-if="info.other.type==='task'" class="item-link" @click="taskDetail(info.other.id)"><span>{{$L('来自关注任务')}}:</span><a href="javascript:void(0)">{{info.other.title}}</a></div>
  43. <div v-if="info.other.type==='file'" class="item-link"><span>{{$L('来自关注任务')}}:</span><a target="_blank" :href="fileDownUrl(info.other.id)">{{info.other.name}}</a></div>
  44. </template>
  45. <div v-else-if="info.type==='report'" class="item-link" @click="reportDetail(info.other.id, info.other.title)"><span>{{$L('来自工作报告')}}:</span><a href="javascript:void(0)">{{info.other.title}}</a></div>
  46. <div v-else-if="info.type==='video' || info.type==='voice'" class="item-link">
  47. <Icon v-if="info.type==='voice'" type="ios-call-outline"/>
  48. <Icon v-else type="ios-videocam-outline"/>
  49. <span>{{$L('通话时长:%', formatSecond(info.other.second))}}</span>
  50. </div>
  51. </div>
  52. </div>
  53. </div>
  54. <!--图片-->
  55. <div v-else-if="info.type==='image'">
  56. <div v-if="info.self===true" class="list-right">
  57. <div v-if="info.error" class="item-error" @click="clickError(info.error)">
  58. <Icon type="md-alert" />
  59. </div>
  60. <div class="item-right">
  61. <div class="item-username" @click="clickUser">
  62. <em class="item-name"><user-view :username="userName" :info="info" placement="left"/></em>
  63. <em v-if="info.indate" class="item-date">{{formatCDate(info.indate)}}</em>
  64. </div>
  65. <a class="item-image" :href="info.url" target="_blank">
  66. <img class="item-image-view" :src="info.url"/>
  67. </a>
  68. </div>
  69. <UserImg :info="info" @click="clickUser" class="item-userimg"/>
  70. </div>
  71. <div v-else-if="info.self===false" class="list-item">
  72. <UserImg :info="info" @click="clickUser" class="item-userimg"/>
  73. <div class="item-left">
  74. <div class="item-username" @click="clickUser">
  75. <em class="item-name"><user-view :username="userName" :info="info" placement="right"/></em>
  76. <em v-if="info.__usertag" class="item-tag">{{info.__usertag}}</em>
  77. <em v-if="info.indate" class="item-date">{{formatCDate(info.indate)}}</em>
  78. </div>
  79. <a class="item-image" :href="info.url" target="_blank">
  80. <img class="item-image-view" :src="info.url"/>
  81. </a>
  82. </div>
  83. </div>
  84. </div>
  85. <!--通知-->
  86. <div v-else-if="info.type==='notice'">
  87. <div class="item-notice">{{info.notice}}</div>
  88. </div>
  89. </div>
  90. </template>
  91. <style lang="scss" scoped>
  92. /*通用*/
  93. .list-item, .list-right {
  94. display: flex;
  95. width: 100%;
  96. padding-top: 7px;
  97. padding-bottom: 7px;
  98. background-color: #E8EBF2;
  99. .item-left, .item-right {
  100. display: flex;
  101. flex-direction: column;
  102. max-width: 80%;
  103. .item-username {
  104. font-size: 12px;
  105. padding-top: 1px;
  106. padding-bottom: 4px;
  107. display: flex;
  108. flex-direction: row;
  109. align-items: center;
  110. em {
  111. display: inline-block;
  112. font-style: normal;
  113. &.item-name {
  114. color: #888888;
  115. }
  116. &.item-tag {
  117. color: #ffffff;
  118. background-color: #ff0000;
  119. line-height: 16px;
  120. padding: 2px 4px;
  121. margin-left: 3px;
  122. border-radius: 2px;
  123. font-size: 12px;
  124. transform: scale(0.8);
  125. font-weight: 600;
  126. }
  127. &.item-date {
  128. margin-left: 4px;
  129. color: #aaaaaa;
  130. }
  131. }
  132. }
  133. }
  134. .item-left {
  135. align-items: flex-start;
  136. }
  137. .item-right {
  138. align-items: flex-end;
  139. .item-username {
  140. text-align: right;
  141. }
  142. .item-link {
  143. transform-origin: right center;
  144. }
  145. }
  146. .item-userimg {
  147. width: 38px;
  148. height: 38px;
  149. margin-left: 8px;
  150. margin-right: 8px;
  151. border-radius: 3px;
  152. font-size: 20px;
  153. }
  154. .item-error {
  155. cursor: pointer;
  156. width: 48px;
  157. position: relative;
  158. > i {
  159. color: #ff0000;
  160. font-size: 18px;
  161. position: absolute;
  162. top: 50%;
  163. left: 50%;
  164. transform: translate(-50%, -50%);
  165. }
  166. }
  167. }
  168. .list-right {
  169. justify-content: flex-end;
  170. }
  171. /*文本*/
  172. .item-text {
  173. display: inline-block;
  174. border-radius: 6px;
  175. padding: 8px;
  176. background-color: #ffffff;
  177. max-height: 580px;
  178. overflow: auto;
  179. &.text-emoji {
  180. background-color: transparent;
  181. .item-text-view {
  182. font-size: 52px;
  183. line-height: normal;
  184. }
  185. }
  186. &.text-error {
  187. box-shadow: 0 0 4px 0 #ffa1a1;
  188. }
  189. .item-text-view {
  190. max-width: 520px;
  191. color: #242424;
  192. font-size: 14px;
  193. line-height: 18px;
  194. word-break: break-all;
  195. }
  196. }
  197. /*信息底标*/
  198. .item-link {
  199. display: flex;
  200. align-items: center;
  201. max-width: 100%;
  202. font-size: 12px;
  203. color: #ffffff;
  204. background-color: #cacaca;
  205. margin-top: 6px;
  206. margin-bottom: -2px;
  207. height: 20px;
  208. line-height: 20px;
  209. padding: 0 5px;
  210. border-radius: 4px;
  211. transform: scale(0.96);
  212. transform-origin: left center;
  213. > i {
  214. font-size: 14px;
  215. padding-right: 2px;
  216. }
  217. > span {
  218. white-space: nowrap;
  219. }
  220. > a {
  221. color: #3D90E2;
  222. padding-left: 3px;
  223. overflow: hidden;
  224. text-overflow: ellipsis;
  225. white-space: nowrap;
  226. max-width: 100%;
  227. }
  228. }
  229. /*图片*/
  230. .item-image {
  231. display: inline-block;
  232. text-decoration: none;
  233. .item-image-view {
  234. max-width: 220px;
  235. max-height: 220px;
  236. border-radius: 6px;
  237. }
  238. }
  239. /*通知*/
  240. .item-notice {
  241. color: #777777;
  242. font-size: 12px;
  243. text-align: center;
  244. padding: 12px 24px;
  245. }
  246. </style>
  247. <script>
  248. export default {
  249. name: 'ChatMessage',
  250. props: {
  251. info: {
  252. type: Object,
  253. default: {},
  254. },
  255. },
  256. mounted() {
  257. },
  258. computed: {
  259. userName() {
  260. return this.info.send_username || this.info.username;
  261. },
  262. userImg() {
  263. return this.info.send_userimg || this.info.userimg;
  264. },
  265. },
  266. methods: {
  267. textMsg(text) {
  268. return (text + "").replace(/\n/, '<br/>');
  269. },
  270. textIsEmoji(text) {
  271. return text.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "_") === "_";
  272. },
  273. formatCDate(v) {
  274. let string = '';
  275. if ($A.runNum(v) > 0) {
  276. if ($A.formatDate('Ymd') === $A.formatDate('Ymd', v)) {
  277. string = $A.formatDate('H:i', v)
  278. } else if ($A.formatDate('Y') === $A.formatDate('Y', v)) {
  279. string = $A.formatDate('m-d', v)
  280. } else {
  281. string = $A.formatDate('Y-m-d', v)
  282. }
  283. }
  284. return string ? '(' + string + ')' : '';
  285. },
  286. clickError(err) {
  287. this.$Modal.error({
  288. title: this.$L("错误详情"),
  289. content: err
  290. });
  291. },
  292. clickUser(e) {
  293. this.$emit('clickUser', this.info, e);
  294. },
  295. fileDownUrl(id) {
  296. return $A.apiUrl('project/files/download?fileid=' + id);
  297. },
  298. formatSecond(d) {
  299. if (d > 3600) {
  300. return Math.ceil(d / 3600) + '小时';
  301. } else if (d > 60) {
  302. return Math.ceil(d / 60) + '分钟';
  303. } else {
  304. return d + '秒';
  305. }
  306. }
  307. }
  308. }
  309. </script>