ny
22 小时以前 282fbc6488f4e8ceb5fda759f963ee88fbf7b999
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<script lang="ts" setup>
import type { ScrollActionType } from '@jnpf/ui';
 
import { onMounted, reactive, ref, toRefs } from 'vue';
 
import { useGlobSetting, useMessage } from '@jnpf/hooks';
import { createImgPreview, ScrollContainer } from '@jnpf/ui';
import { formatToDateTime } from '@jnpf/utils';
 
import { delComment, getCommentList } from '#/api/workFlow/template';
import emojiJson from '#/layouts/header/chat/emoji.json';
import { getAuthMediaUrl } from '#/utils/jnpf';
 
import CommentInput from './CommentInput.vue';
 
interface State {
  list: any[];
  loading: boolean;
  listQuery: any;
}
 
const props = defineProps({
  taskId: { type: [String, Number], default: '' },
});
 
const { createMessage } = useMessage();
const globSetting = useGlobSetting();
const apiUrl = ref(globSetting.apiURL);
const infiniteBody = ref<Nullable<ScrollActionType>>(null);
const state = reactive<State>({
  list: [],
  loading: false,
  listQuery: {
    currentPage: 1,
    pageSize: 100000,
    sort: 'desc',
    sidx: '',
  },
});
const { list, loading } = toRefs(state);
 
function handleReply(item, index) {
  item.commentActive = true;
  for (let i = 0; i < state.list.length; i++) {
    if (i != index) state.list[i].commentActive = false;
  }
}
function handleDel(id) {
  delComment(id).then((res) => {
    createMessage.success(res.msg);
    init();
  });
}
function handlePreview(list, index) {
  const imageList = list.map((o) => getAuthMediaUrl(o.url));
  createImgPreview({ imageList, index });
}
function replaceEmoji(str) {
  if (!str) return '';
  // 替换表情符号为图片
  const replacedStr = str.replaceAll(/\[([^(\]|[)]*)\]/g, (item) => {
    let obj = '';
    for (const row of emojiJson) {
      if (row.alt == item) {
        obj = `<img src="/resource/emoji/${row.url}" class="comment-text-emoji" />`;
        break;
      }
    }
    return obj || str;
  });
  str = replacedStr;
  return str;
}
function init() {
  if (!props.taskId) return;
  state.loading = true;
  const query = { ...state.listQuery, taskId: props.taskId };
  getCommentList(query)
    .then((res) => {
      const list = res.data.list.map((o) => ({
        ...o,
        text: replaceEmoji(o.text),
        replyText: replaceEmoji(o.replyText),
        fileList: o.file ? JSON.parse(o.file) : [],
        imageList: o.image ? JSON.parse(o.image) : [],
        creatorTime: formatToDateTime(o.creatorTime),
      }));
      state.list = list;
      state.loading = false;
    })
    .catch(() => {
      state.loading = false;
    });
}
 
onMounted(() => {
  init();
});
</script>
<template>
  <div class="form-extra-comment">
    <ScrollContainer v-loading="loading" ref="infiniteBody" class="form-extra-comment-main">
      <div class="form-extra-comment-list">
        <div v-for="(item, i) in list" :key="i" class="form-extra-comment-item">
          <div class="form-extra-comment-item-main">
            <a-avatar :size="24" :src="apiUrl + item.creatorUserHeadIcon" class="comment-avatar" />
            <div class="comment-content">
              <div class="comment-head">
                <p class="username">
                  {{ item.creatorUser }}
                  <span v-if="item.replyUser">
                    <span class="replay-separate">回复</span>
                    {{ item.replyUser }}
                    <a-tooltip>
                      <template #title>
                        <div v-html="item.replyText"></div>
                      </template>
                      <i class="icon-ym icon-ym-chat"></i>
                    </a-tooltip>
                  </span>
                </p>
              </div>
              <p class="comment-text" v-html="item.isDel == 2 ? '该评论已被删除' : item.text"></p>
              <div class="comment-other" v-if="item.isDel != 2 && (item.imageList?.length || item.fileList?.length)">
                <div class="comment-img-list" v-if="item.imageList?.length">
                  <img
                    :src="getAuthMediaUrl(cItem.url)"
                    class="comment-img-item"
                    v-for="(cItem, ci) in item.imageList"
                    :key="ci"
                    @click="handlePreview(item.imageList, ci)" />
                </div>
                <div class="comment-file-List" v-if="item.fileList?.length">
                  <jnpf-upload-file v-model:value="item.fileList" detailed disabled :show-all-download="false" />
                </div>
              </div>
              <div class="comment-actions">
                <span class="time">{{ item.creatorTime }}</span>
                <div v-if="item.isDel != 2">
                  <a-popconfirm title="确定删除该评论?" @confirm="handleDel(item.id)" v-if="item.isDel == 1">
                    <a-button type="link" color="error">删除</a-button>
                  </a-popconfirm>
                  <a-button type="link" class="ml-[10px]" @click="handleReply(item, i)">回复</a-button>
                </div>
              </div>
            </div>
          </div>
          <CommentInput inner :task-id="taskId" :reply-id="item.id" v-if="item.commentActive" @hide-comment-input="item.commentActive = false" @reload="init" />
        </div>
      </div>
      <jnpf-empty v-if="!list.length" />
    </ScrollContainer>
    <div class="form-extra-comment-list-footer">
      <CommentInput :task-id="taskId" @reload="init" />
    </div>
  </div>
</template>