cocoFlowDia.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. <template>
  2. <div>
  3. <el-dialog
  4. :visible.sync="FlowVisible"
  5. width="90%"
  6. class="dialog_diy"
  7. :close-on-click-modal="false"
  8. :fullscreen="markfullscreen"
  9. :style="{ '--dialog-height': markfullscreen ? '100%' : '95%' }"
  10. :before-close="handleClose">
  11. <div slot="title">
  12. <div class="markScore_diyTit">
  13. <div>{{ lang.ssViewWork }}</div>
  14. <img @click="markFullScreenBtn" style="cursor: pointer;height: 16px;" src="../../assets/icon/svgImg/nrk_fullscreen.svg" alt="" />
  15. </div>
  16. </div>
  17. <div class="markDialog">
  18. <template v-if="listData.length && showListData(listData)">
  19. <div v-for="(item,index) in listData" :key="index">
  20. <div class="BodyCon" v-if="item.imageUrls && item.imageUrls.length">
  21. <div class="BodyConTit">{{ lang.ssNodeLabel.replace(/\*/g, index + 1) }}</div>
  22. <div style="display: flex;flex-wrap: wrap;gap: 10px;">
  23. <img
  24. style="max-width: 360px;object-fit: cover;cursor: pointer;"
  25. v-for="(image,imgIndex) in item.imageUrls"
  26. :key="index+'-image-'+imgIndex"
  27. :src="image"
  28. alt=""
  29. @click="previewImage(image)"
  30. />
  31. </div>
  32. </div>
  33. <div class="BodyCon" v-if="item.messages && item.messages.length" >
  34. <div class="BodyConTit">{{ lang.ssNodeLabel.replace(/\*/g, index + 1) }}</div>
  35. <div class="BodyConChat" v-for="(po, index2) in item.messages" :key="index+'-'+index2">
  36. <div class="left" v-if="po.role == 'assistant'">
  37. <div class="TName" style="background-color: #0560FD;">{{ lang.ssXiaoKeAIAssistant }}</div>
  38. <div class="con" v-html="MarkdownT(po.content)"></div>
  39. </div>
  40. <div class="left" v-if="po.role == 'user'">
  41. <div class="TName" style="background-color: #9747FF;">{{ username }}</div>
  42. <div class="con" v-html="po.content"></div>
  43. </div>
  44. </div>
  45. </div>
  46. </div>
  47. </template>
  48. <div v-else style="text-align: center;
  49. display: flex;
  50. justify-content: center;
  51. align-items: center;
  52. height: 100%;
  53. min-height: 500px;">
  54. {{ lang.ssWorkOnlyShowsDialog }}
  55. </div>
  56. </div>
  57. </el-dialog>
  58. <!-- 图片预览对话框 -->
  59. <el-dialog
  60. :visible.sync="imagePreviewVisible"
  61. width="90%"
  62. :close-on-click-modal="true"
  63. :show-close="true"
  64. class="image-preview-dialog"
  65. @close="imagePreviewVisible = false">
  66. <div style="text-align: center;">
  67. <img
  68. :src="previewImageUrl"
  69. :alt="lang.ssPreviewImage"
  70. style="max-width: 100%; max-height: 80vh; object-fit: contain;"
  71. />
  72. </div>
  73. </el-dialog>
  74. </div>
  75. </template>
  76. <script>
  77. import MarkdownIt from "markdown-it";
  78. const getFile = url => {
  79. return new Promise((resolve, reject) => {
  80. var credentials = {
  81. accessKeyId: "AKIATLPEDU37QV5CHLMH",
  82. secretAccessKey: "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"
  83. }; //秘钥形式的登录上传
  84. window.AWS.config.update(credentials);
  85. window.AWS.config.region = "cn-northwest-1"; //设置区域
  86. let url2 = url;
  87. let _url2 = "";
  88. if (
  89. url2.indexOf("https://view.officeapps.live.com/op/view.aspx?src=") != -1
  90. ) {
  91. _url2 = url2.split(
  92. "https://view.officeapps.live.com/op/view.aspx?src="
  93. )[1];
  94. } else {
  95. _url2 = url2;
  96. }
  97. var s3 = new window.AWS.S3({ params: { Bucket: "ccrb" } });
  98. let name = decodeURIComponent(
  99. _url2.split("https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/")[1]
  100. );
  101. var params = {
  102. Bucket: "ccrb",
  103. Key: name
  104. };
  105. s3.getObject(params, function(err, data) {
  106. if (err) {
  107. console.log(err, err.stack);
  108. resolve({ data: 1 });
  109. } else {
  110. const fileContent = data.Body.toString("utf-8");
  111. resolve({ data: fileContent });
  112. } // sxuccessful response
  113. });
  114. // axios({
  115. });
  116. };
  117. import { myMixin } from "@/mixins/mixin.js"
  118. export default {
  119. mixins: [ myMixin ],
  120. data() {
  121. return {
  122. username:'',
  123. FlowVisible:false,
  124. listData:[],
  125. markfullscreen:false,
  126. imagePreviewVisible: false,
  127. previewImageUrl: ''
  128. }
  129. },
  130. computed: {
  131. showListData(){
  132. return function (val) {
  133. let kk = val.map(e=> e.messages).flat()
  134. console.log('kk',kk);
  135. if (!kk.length || kk.every(v => v == null || v === 'undefined' || v === '')) {
  136. return false
  137. }
  138. return true
  139. };
  140. },
  141. MarkdownT() {
  142. return function (c) {
  143. let md = new MarkdownIt({
  144. html: true, // 允许渲染 HTML
  145. linkify: true, // 自动将URL链接转化为可点击链接
  146. typographer: true, // 启用排版规则(如替换 `"` 为 “)
  147. });
  148. const renderedContent = c ? md.render(c) : "";
  149. // 使用正则表达式替换链接
  150. const result = renderedContent.replace(/<a href="([^"]+)">([^<]*)<\/a>/g, (match, url, text) => {
  151. // 判断链接是否为图片格式
  152. if (/\.(png|jpg|jpeg|gif|bmp|svg)$/i.test(url)) {
  153. // 返回<img>标签
  154. return `<img src="${url}" alt="${text}" />`;
  155. } else {
  156. // 返回原来的<a>标签
  157. return match;
  158. }
  159. });
  160. return result;
  161. }
  162. }
  163. },
  164. methods: {
  165. // 评分弹框全屏
  166. markFullScreenBtn() {
  167. this.markfullscreen = !this.markfullscreen;
  168. },
  169. async openAppWork(val){
  170. console.log(val);
  171. // val.works = 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/pptData1764063222122.json'
  172. // let kk = 'https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/pptData1764063222122.json'
  173. // console.log('this.isValidURL(val.works)',this.isValidURL(val.works));
  174. if (this.isValidURL(val.works)) {
  175. await getFile(val.works).then((res) => {
  176. val.works = res.data;
  177. });
  178. }
  179. this.username = val.sName
  180. try {
  181. this.listData = JSON.parse(val.works)
  182. } catch (error) {
  183. this.listData = []
  184. }
  185. this.FlowVisible = true;
  186. },
  187. isValidURL(str){
  188. try {
  189. const url = new URL(str);
  190. return ['http:', 'https:', 'ftp:'].includes(url.protocol) && !!url.hostname;
  191. } catch (e) {
  192. return false;
  193. }
  194. },
  195. handleClose(){
  196. this.listData = []
  197. this.FlowVisible = false;
  198. },
  199. // 预览图片
  200. previewImage(imageUrl) {
  201. this.previewImageUrl = imageUrl;
  202. this.imagePreviewVisible = true;
  203. },
  204. },
  205. }
  206. </script>
  207. <style scoped>
  208. .dialog_diy {
  209. min-width: 800px;
  210. display: flex;
  211. }
  212. .dialog_diy >>> .el-dialog__header {
  213. background: #fff !important;
  214. padding: 15px 20px;
  215. border-radius: 12px 12px 0 0 !important;
  216. border-bottom: 1px #E7E7E7 solid;
  217. }
  218. .dialog_diy >>> .el-dialog{
  219. border-radius: 12px;
  220. overflow: hidden;
  221. height: var(--dialog-height, 95%) !important;
  222. margin: auto !important;
  223. display: flex;
  224. flex-direction: column;
  225. }
  226. .dialog_diy >>> .el-dialog__title{
  227. color: #fff;
  228. }
  229. .dialog_diy >>> .el-dialog__headerbtn {
  230. top: 19px;
  231. }
  232. .dialog_diy >>> .el-dialog__headerbtn .el-dialog__close{
  233. color: #000;
  234. }
  235. .dialog_diy >>> .el-dialog__headerbtn .el-dialog__close:hover {
  236. color: #000;
  237. }
  238. .dialog_diy >>> .el-dialog__body{
  239. background: #FFFFFFCC;
  240. border-radius: 12px !important;
  241. overflow: auto;
  242. box-sizing: border-box;
  243. flex: 1;
  244. min-height: 0;
  245. max-height: none;
  246. padding: 0 !important;
  247. margin: 0;
  248. width: 100%;
  249. }
  250. .dialog_diy >>> .el-dialog__body::-webkit-scrollbar-thumb {
  251. background-color: #0560FD; /* 设置滚动条滑块颜色 */
  252. }
  253. .markDialog{
  254. height: auto;
  255. min-height: 100%;
  256. display: flex;
  257. padding:12px 30px 24px;
  258. box-sizing: border-box;
  259. flex-direction: column;
  260. gap: 30px;
  261. }
  262. .markScore_diyTit {
  263. color: #000000;
  264. width: calc(100% - 50px);
  265. display: flex;
  266. height: 24px;
  267. justify-content: space-between;
  268. align-items: center;
  269. font-family: PingFang SC;
  270. }
  271. .TName{
  272. color: #fff;
  273. font-weight: 600;
  274. width: 185px;
  275. flex-shrink: 0;
  276. overflow: hidden;
  277. white-space: nowrap;
  278. text-overflow: ellipsis;
  279. border-radius: 12px 12px 0 0;
  280. height: 28px;
  281. padding: 6px 17px;
  282. box-sizing: border-box;
  283. display: flex;
  284. align-items: center;
  285. }
  286. .con{
  287. color: #000000E5;
  288. border-radius: 0 0 12px 12px;
  289. border: 1px solid #E7E7E7;
  290. padding: 16px;
  291. box-sizing: border-box;
  292. box-shadow: 0px 4px 20px 0px #0000001A;
  293. }
  294. .left{
  295. display: flex;
  296. flex-direction: column;
  297. font-size: 16px !important;
  298. justify-content: flex-start;
  299. line-height: 25px;
  300. }
  301. .BodyCon{
  302. background: #FFFFFF;
  303. border: 0.5px solid #E7E7E7;
  304. border-radius: 12px;
  305. padding: 10px;
  306. box-sizing: border-box;
  307. display: flex;
  308. flex-direction: column;
  309. gap: 10px;
  310. }
  311. .BodyConTit{
  312. font-family: PingFang SC;
  313. font-weight: 500;
  314. font-size: 16px;
  315. line-height: 24px;
  316. color: #000;
  317. }
  318. .BodyConChat{
  319. display: flex;
  320. flex-direction: column;
  321. /* border-radius: 0 0 12px 12px;
  322. border: 1px solid #E7E7E7;
  323. padding: 16px;
  324. box-sizing: border-box; */
  325. }
  326. /* 图片预览对话框样式 */
  327. .image-preview-dialog >>> .el-dialog__body {
  328. padding: 20px;
  329. /* background: rgba(0, 0, 0, 0.8); */
  330. display: flex;
  331. justify-content: center;
  332. align-items: center;
  333. }
  334. .image-preview-dialog >>> .el-dialog {
  335. background: transparent;
  336. box-shadow: none;
  337. }
  338. .image-preview-dialog >>> .el-dialog__header {
  339. background: transparent;
  340. border: none;
  341. }
  342. .image-preview-dialog >>> .el-dialog__close {
  343. color: #fff;
  344. font-size: 24px;
  345. }
  346. .image-preview-dialog >>> .el-dialog__close:hover {
  347. color: #409EFF;
  348. }
  349. </style>