<script lang="ts" setup>
|
import type { ScrollActionType } from '@jnpf/ui';
|
|
import { nextTick, onMounted, reactive, ref, toRefs } from 'vue';
|
|
import { useGlobSetting } from '@jnpf/hooks';
|
import { ScrollContainer } from '@jnpf/ui';
|
|
import { Timeline, TimelineItem } from 'ant-design-vue';
|
|
import { getDataLogList } from '#/api/onlineDev/visualDev';
|
|
import { parseAuditFieldDiffs } from './auditDiff';
|
import AuditDiffList from './AuditDiffList.vue';
|
|
interface State {
|
list: any[];
|
loading: boolean;
|
finish: boolean;
|
listQuery: any;
|
}
|
|
const props = defineProps({
|
modelId: { type: String, default: '' },
|
formDataId: { type: [String, Number], default: '' },
|
});
|
|
const globSetting = useGlobSetting();
|
const apiUrl = ref(globSetting.apiURL);
|
const infiniteBody = ref<Nullable<ScrollActionType>>(null);
|
const state = reactive<State>({
|
list: [],
|
loading: false,
|
finish: false,
|
listQuery: {
|
currentPage: 1,
|
pageSize: 20,
|
sort: 'desc',
|
sidx: '',
|
},
|
});
|
const { list, loading } = toRefs(state);
|
function bindScroll() {
|
const bodyRef = infiniteBody.value;
|
const vBody = bodyRef?.getScrollWrap();
|
vBody?.addEventListener('scroll', () => {
|
if (vBody.scrollHeight - vBody.clientHeight - vBody.scrollTop <= 200 && !state.loading && !state.finish) {
|
state.listQuery.currentPage += 1;
|
init();
|
}
|
});
|
}
|
function getNodeStatusColor(type) {
|
if (type == 1) return 'blue';
|
if (type == 0) return 'success';
|
return 'warning';
|
}
|
function getTimeLineTagColor(type) {
|
if (type == 1) return '#0177FF';
|
if (type == 0) return '#08AF28';
|
return '#FA8C16';
|
}
|
function getNodeStatusContent(item) {
|
if (item.actionLabel) return item.actionLabel;
|
return item.type == 1 ? '编辑' : '新建';
|
}
|
function init() {
|
if (!props.modelId || !props.formDataId) return;
|
state.loading = true;
|
getDataLogList({ ...state.listQuery, modelId: props.modelId, dataId: props.formDataId })
|
.then((res) => {
|
const rawList = res.data.list || [];
|
if (rawList.length < state.listQuery.pageSize) state.finish = true;
|
const list = rawList.map((o) => {
|
const dataLogRaw = o.dataLog ?? o.data_log;
|
const parsedDiffs = parseAuditFieldDiffs(dataLogRaw);
|
return {
|
...o,
|
creatorTime: o.creatorTime ?? o.creator_time,
|
creatorUserName: o.creatorUserName ?? o.creator_user_name,
|
creatorUserId: o.creatorUserId ?? o.creator_user_id,
|
headIcon: o.headIcon ?? o.head_icon,
|
actionType: o.actionType ?? o.action_type,
|
actionLabel: o.actionLabel ?? o.action_label,
|
dataLog: parsedDiffs.diffs,
|
dataLogParseError: parsedDiffs.parseError,
|
};
|
});
|
state.list = [...state.list, ...list];
|
state.loading = false;
|
})
|
.catch(() => {
|
state.loading = false;
|
});
|
}
|
|
onMounted(() => {
|
state.list = [];
|
state.finish = false;
|
init();
|
nextTick(() => {
|
bindScroll();
|
});
|
});
|
</script>
|
<template>
|
<div class="form-extra-log">
|
<ScrollContainer v-loading="loading" ref="infiniteBody" class="form-extra-comment-main">
|
<Timeline class="form-extra-log-list" v-if="list.length">
|
<TimelineItem v-for="(item, index) in list" :key="index">
|
<template #dot>
|
<span class="tag" :style="{ background: getTimeLineTagColor(item.type) }"></span>
|
</template>
|
<span>{{ item.creatorTime }}</span>
|
<div class="time-item-container">
|
<div class="time-item-head">
|
<a-avatar :size="24" :src="apiUrl + item.headIcon" class="head-avatar" />
|
<span class="head-name">{{ item.creatorUserName }}</span>
|
<a-tag :color="getNodeStatusColor(item.type)" :bordered="false" class="head-status">{{ getNodeStatusContent(item) }}</a-tag>
|
</div>
|
<AuditDiffList
|
class="time-item-log"
|
v-if="item.type && (item.dataLog?.length || item.dataLogParseError)"
|
:diffs="item.dataLog"
|
:parse-error="item.dataLogParseError" />
|
</div>
|
</TimelineItem>
|
</Timeline>
|
<jnpf-empty v-if="!list.length" />
|
</ScrollContainer>
|
</div>
|
</template>
|