Merge branch 'test' into shen

# Conflicts:
#	src/views/final/content/Content.vue
pull/65/head
Dragon 1 year ago
commit e174903ebb

@ -83,7 +83,7 @@ export async function getTaskDetailInfo(checkDuplicateId: string) {
* @param params
* @returns
*/
export async function getTaskDetailPictureList(params: PageParam & PictureSortParam & SimilarityPictureSortParam) {
export async function getPictureSimilarityList(params: PageParam & PictureSortParam & SimilarityPictureSortParam) {
const res = await http.request({
url: `/backstage/jifen/ocrtaskchildpicture/getPictureSimilarityList`,
@ -97,6 +97,7 @@ export async function getTaskDetailPictureList(params: PageParam & PictureSortPa
const list = records.map((item,index) => {
return {
id: item.id,
checkDuplicateId: item.checkDuplicateId,
taskId: item.taskId,
taskname: item.fromTaskName,
assignee: item.assignee,

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 20 20">
<path fill="#f6c042" d="M2.93 17.07A10 10 0 1 1 17.07 2.93A10 10 0 0 1 2.93 17.07M9 5v6h2V5zm0 8v2h2v-2z" />
</svg>

After

Width:  |  Height:  |  Size: 203 B

@ -0,0 +1,114 @@
<script lang="ts" setup>
import { onBeforeMount, ref } from 'vue';
const emit = defineEmits<{
(e: 'commit')
}>()
const props = defineProps({
selectedTotal: {
type: Number,
default: () => 0,
}
})
const show = ref(false)
const cardStyle = {
'width': '450px',
'--n-padding-top': '20px',
'--n-padding-bottom': '20px',
'--n-padding-left': '20px',
'--n-padding-right': '20px',
}
function showModal() {
show.value = true
}
function closeModal() {
show.value = false
}
defineExpose({
showModal,
})
async function handleSumbit(e: MouseEvent) {
e.preventDefault()
closeModal()
emit('commit')
}
onBeforeMount(async () => { })
</script>
<template>
<n-modal v-model:show="show" transform-origin="center">
<n-card :style="cardStyle" :bordered="false" size="huge" role="dialog" aria-modal="true">
<div class="wrapper">
<div class="wrapper-header">
<SvgIcon name="exclamation-solid" size="16" />
<span class="wrapper-left">确认提示</span>
</div>
<div class="wrapper-content">
已选<span class="highlighted-text">{{ props.selectedTotal }}</span>张图片确认将所选照片移除可疑夹吗
</div>
</div>
<template #footer>
<div class="wrapper-footer">
<n-button type="info" @click="handleSumbit">
确定
</n-button>
<n-button secondary style="margin-left:15px" @click="closeModal">
取消
</n-button>
</div>
</template>
</n-card>
</n-modal>
</template>
<style lang="less" scoped>
.wrapper {
&-header {
display: flex;
justify-content: flex-start;
align-items: center;
padding: 10px;
}
&-left {
font-weight: 600;
font-size: 16px;
margin-left: 15px;
}
&-content {
margin-left: 15px;
color: #8e8e8e;
.highlighted-text {
color: #5b85f8;
margin: 0 5px;
}
}
&-footer {
display: flex;
justify-content: flex-end;
}
}
::v-deep(.n-card.n-card--content-segmented > .n-card__content:not(:first-child)) {
border: 0px;
}
::v-deep(.n-card > .n-card-header) {
--n-padding-top: 0px;
--n-padding-bottom: 12px;
}
::v-deep(.n-divider:not(.n-divider--vertical)) {
margin-top: 0px;
margin-bottom: 0px;
}
</style>

@ -12,6 +12,7 @@ import { debounce } from 'lodash-es'
import { audit } from '@/api/task/task'
import NotPassed from '@/components/Approval/NotPassed.vue'
import { off, on } from '@/utils/domUtils'
import ConfrimModal from "./ConfrimModal.vue"
const cardStyle = {
'--n-padding-bottom': '40px',
@ -59,6 +60,7 @@ const show = ref(false)
const selectedApproveItems = ref<any[]>([]); //
const dialog = useDialog();
let processItems: any[] = [];
const confrimModalRef = ref<any>();
const layout = debounce(() => {
if (!show.value)
@ -252,14 +254,8 @@ function closeModal(event: MouseEvent) {
selectedApproveItems.value = []
show.value = false
}
async function remove() {
if ( !selectIds.value|| selectIds.value.length === 0) {
message.error('至少选中一个')
return
}
const ids = selectIds.value.join(',')
async function commit() {
const ids = selectIds.value.join(',')
const res = await removeFiles({ pictureid: ids })
if (res.code === 'OK') {
message.success('移除成功')
@ -269,6 +265,13 @@ async function remove() {
layout()
}
}
function remove() {
if ( !selectIds.value|| selectIds.value.length === 0) {
message.error('至少选中一个')
return
}
confrimModalRef?.value?.showModal()
}
function setBatch(value) {
@ -288,11 +291,9 @@ defineExpose({
showModal,
})
const checked = ref(false)
const notPassModalRef = ref(null)
const showActions = computed(() => {
console.log('selectedApproveItems',selectedApproveItems)
console.log('selectedApproveItems', selectedApproveItems)
return selectedApproveItems.value.length > 0 && batch;
});
@ -385,7 +386,7 @@ function doAudit(param: any) {
function reloadList() {
refreshHandler()
}
function refreshHandler(){
function refreshHandler() {
reset()
featchList()
}
@ -394,14 +395,10 @@ function refreshHandler(){
<template>
<div>
<n-modal
v-model:show="show" :mask-closable="false" style="position: relative;" transform-origin="center"
@after-enter="afterEnter" @after-leave="afterLeave"
>
<n-card
:style="cardStyle" class="card card-1" style="position: fixed;top:64px" :bordered="false" size="huge" role="dialog"
aria-modal="true"
>
<n-modal v-model:show="show" :mask-closable="false" style="position: relative;" transform-origin="center"
@after-enter="afterEnter" @after-leave="afterLeave">
<n-card :style="cardStyle" class="card card-1" style="position: fixed;top:64px" :bordered="false" size="huge"
role="dialog" aria-modal="true">
<div class="wrapper">
<div class="wrapper-m32">
<SvgIcon name="recycle" size="16" />
@ -436,45 +433,37 @@ function refreshHandler(){
批量审批
</div>
<div v-show="showActions" class="batch">
<n-button text @click="setBatch(false)">
<template #icon>
<SvgIcon name="revoke" />
</template>
返回
</n-button>
<div style="cursor: pointer; margin-left: 16px" @click.stop="rejectHandler">
<SvgIcon width="64" height="28" name="a1" />
</div>
<SvgIcon size="24" name="vs" />
<div style="cursor: pointer" @click.stop="approvalHandler">
<SvgIcon width="64" height="28" name="a2" />
</div>
<n-button text @click="setBatch(false)">
<template #icon>
<SvgIcon name="revoke" />
</template>
返回
</n-button>
<div style="cursor: pointer; margin-left: 16px" @click.stop="rejectHandler">
<SvgIcon width="64" height="28" name="a1" />
</div>
<SvgIcon size="24" name="vs" />
<div style="cursor: pointer" @click.stop="approvalHandler">
<SvgIcon width="64" height="28" name="a2" />
</div>
</div>
</div>
</div>
<div ref="el" class="scroll">
<!-- <n-scrollbar :on-scroll="scrollHandler"> -->
<div ref="masonryRef" class="grid">
<div
v-for="(item, index) in listData" :key="item.id" :data-id="item.id"
:class="{ 'grid-item-selected': isSelected(item.id) }" :style="{ height: gridHeight }" class="grid-item"
>
<div v-for="(item, index) in listData" :key="item.id" :data-id="item.id"
:class="{ 'grid-item-selected': isSelected(item.id) }" :style="{ height: gridHeight }"
class="grid-item">
<!-- <img
class="wrapper-content-item-img"
:class="{ 'wrapper-content-item-img-fit': viewMode !== 'masonry' }" :src="item.imgUrl"
> -->
<n-image
:src="item.imgurl"
class="img "
:class="{ 'img-fit': viewMode === 'horizontalVersion', 'img-full': viewMode === '3:4' || viewMode === 'verticalVersion' }"
/>
<n-checkbox
v-if="batch"
v-model:checked="item.checked"
style="position:absolute;left:20px;top:20px" @click.prevent
@update:checked="onCheckChange($event, item)"
/>
<n-image :src="item.imgurl" class="img "
:class="{ 'img-fit': viewMode === 'horizontalVersion', 'img-full': viewMode === '3:4' || viewMode === 'verticalVersion' }" />
<n-checkbox v-if="batch" v-model:checked="item.checked" style="position:absolute;left:20px;top:20px"
@click.prevent @update:checked="onCheckChange($event, item)" />
<!-- <div class="percent">
{{ getPercent(item.pictureid, item) }}
</div> -->
@ -491,6 +480,7 @@ function refreshHandler(){
</n-card>
</n-modal>
<NotPassed ref="notPassModalRef" @success="reloadList" />
<ConfrimModal ref="confrimModalRef" @commit="commit" :selectedTotal="selectIds.length"/>
</div>
</template>
@ -502,11 +492,9 @@ function refreshHandler(){
user-select: none;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
/* Standard syntax */
}
.remove{
.remove {
cursor: pointer;
}
@ -538,7 +526,7 @@ function refreshHandler(){
}
}
.img{
.img {
border-radius: 8px;
}
@ -553,7 +541,7 @@ function refreshHandler(){
padding: 24px 0px 12px 0px;
}
&-m32{
&-m32 {
margin-left: 32px;
}
@ -636,21 +624,23 @@ function refreshHandler(){
}
}
.wrapper-content-form-button{
.wrapper-content-form-button {
cursor: pointer;
}
.img-fit {
width: 100%;
overflow: hidden;
}
.img-full {
width: 100%;
overflow: hidden;
::v-deep(img) {
width: 100%;
height: 100%;
object-fit: cover;
}
}
width: 100%;
overflow: hidden;
}
.img-full {
width: 100%;
overflow: hidden;
::v-deep(img) {
width: 100%;
height: 100%;
object-fit: cover;
}
}
</style>

@ -11,7 +11,9 @@ export const useWorkOrderStore = defineStore({
activeId: '',
packageList: [],
immersion: false,
name: ''
name: '',
dataId: '',
approvalList: [],
}),
getters: {
getActiveId: (state: OrderState) => state.activeId,
@ -22,10 +24,11 @@ export const useWorkOrderStore = defineStore({
setOrderList(list: PackageListItem[]) {
this.packageList = list
},
setActive(index: number, orderId?: string) {
setActive(index: number, orderId?: string, dataId?: string) {
this.currentIndex = index
const order = this.packageList[index]
this.activeId = orderId || order?.checkDuplicateId
this.dataId = dataId || order.id;
},
forward() {
const len = this.packageList.length
@ -46,7 +49,7 @@ export const useWorkOrderStore = defineStore({
},
async fetchOrderList(pagination, keyword) {
const res = await getPackageList(pagination, keyword)
if (res.data&&res.data.length > 0) {
if (res.data && res.data.length > 0) {
this.packageList.push(...res.data)
if (!this.activeId)
this.setActive(0)

@ -1,162 +1,178 @@
<script lang="ts" setup>
import { computed, inject, nextTick, onBeforeMount, onMounted, reactive, ref, shallowRef, unref, watch } from 'vue'
import { CustomFilterModalVue, FilterModal, NewFilterModal } from '@/views/final/comp'
import Search from '@/views/home/aside/comp/Search.vue'
import AdvanceFilter from '@/views/home/aside/comp/AdvanceFilter.vue'
import { getViewportOffset } from '@/utils/domUtils'
import { useWindowSizeFn } from '@/hooks/event/useWindowSizeFn'
import { useFinal } from '@/store/modules/final'
import type { Filter } from '/#/home'
import type { AsideEntity } from '@/config/aside'
import { asideMap } from '@/config/final'
import type { AsideConfig } from '/#/api'
import emitter from '@/utils/mitt'
const finalStore = useFinal()
import {
computed,
inject,
nextTick,
onBeforeMount,
onMounted,
reactive,
ref,
shallowRef,
unref,
watch,
} from "vue";
import { CustomFilterModalVue, FilterModal, NewFilterModal } from "@/views/final/comp";
import Search from "@/views/home/aside/comp/Search.vue";
import AdvanceFilter from "@/views/home/aside/comp/AdvanceFilter.vue";
import { getViewportOffset } from "@/utils/domUtils";
import { useWindowSizeFn } from "@/hooks/event/useWindowSizeFn";
import { useFinal } from "@/store/modules/final";
import type { Filter } from "/#/home";
import type { AsideEntity } from "@/config/aside";
import { asideMap } from "@/config/final";
import type { AsideConfig } from "/#/api";
import emitter from "@/utils/mitt";
const emit = defineEmits(["inputChange"]);
const finalStore = useFinal();
//
const asideValue: Record<keyof typeof asideMap, any> = reactive({})
const asideValue: Record<keyof typeof asideMap, any> = reactive({});
// :
const asideVisible: Partial<Record<keyof AsideConfig, boolean>> = reactive({})
const asideVisible: Partial<Record<keyof AsideConfig, boolean>> = reactive({});
//
const showItems = shallowRef<{ key: string, config: AsideEntity }[]>([])
const showItems = shallowRef<{ key: string; config: AsideEntity }[]>([]);
Object.keys(asideMap).forEach((key) => {
const { defaultValue, inFilterList } = asideMap[key]
if (inFilterList !== false)
asideValue[key] = defaultValue
})
const { defaultValue, inFilterList } = asideMap[key];
if (inFilterList !== false) asideValue[key] = defaultValue;
});
const filterModalRef = ref(null)
const newFilterModalRef = ref(null)
const customModalRef = ref(null)
const filterModalRef = ref(null);
const newFilterModalRef = ref(null);
const customModalRef = ref(null);
function showModal(modalRef: any) {
const modal = unref(modalRef)! as any
modal.showModal()
const modal = unref(modalRef)! as any;
modal.showModal();
}
const mousetrap = inject('mousetrap') as any
mousetrap.bind('[', collapseHandler)
const mousetrap = inject("mousetrap") as any;
mousetrap.bind("[", collapseHandler);
onMounted(() => {
nextTick(() => {
computeSlideHeight()
})
})
computeSlideHeight();
});
});
const collapse = ref(false)
const collapse = ref(false);
function collapseHandler() {
collapse.value = !collapse.value
collapse.value = !collapse.value;
}
const asideWidth = computed(() => {
return collapse.value ? 0 : 308
})
return collapse.value ? 0 : 308;
});
const asideHeight = ref(500)
const asideHeight = ref(500);
const asideStyle = computed(() => {
return {
width: `${asideWidth.value}px`,
height: `${asideHeight.value}px`,
}
})
};
});
const collapseIcon = computed(() => {
return collapse.value ? 'expand-cir' : 'collapse-cir'
})
return collapse.value ? "expand-cir" : "collapse-cir";
});
function computeSlideHeight() {
const headEl = document.querySelector('.aside-header')!
const { bottomIncludeBody } = getViewportOffset(headEl)
const height = bottomIncludeBody
asideHeight.value = height - 24
const headEl = document.querySelector(".aside-header")!;
const { bottomIncludeBody } = getViewportOffset(headEl);
const height = bottomIncludeBody;
asideHeight.value = height - 24;
}
useWindowSizeFn(computeSlideHeight, 280)
useWindowSizeFn(computeSlideHeight, 280);
onBeforeMount(async () => {
finalStore.fetchCustomConfig()
})
finalStore.fetchCustomConfig();
});
finalStore.$subscribe(() => {
const customConfig = finalStore.getCustomConfig
const customConfig = finalStore.getCustomConfig;
if (customConfig === null)
return
if (customConfig === null) return;
const showKeys: string[] = [...customConfig]
const defaultKeys = Object.keys(asideMap).filter(key => asideMap[key].isDefaultFilter)
showKeys.unshift(...defaultKeys)
const showKeys: string[] = [...customConfig];
const defaultKeys = Object.keys(asideMap).filter(
(key) => asideMap[key].isDefaultFilter
);
showKeys.unshift(...defaultKeys);
Object.keys(asideMap).forEach((key) => {
//
if (key.startsWith('iz'))
asideVisible[key] = asideMap[key] && (showKeys.includes(key) || asideMap[key].isDefaultFilter)
})
if (key.startsWith("iz"))
asideVisible[key] =
asideMap[key] && (showKeys.includes(key) || asideMap[key].isDefaultFilter);
});
const items = showKeys.reduce((acc, key) => {
if (asideMap[key]) {
const config = {
key,
config: asideMap[key],
}
return [...acc, config]
}
else {
return acc
};
return [...acc, config];
} else {
return acc;
}
}, [])
}, []);
showItems.value = items
})
showItems.value = items;
});
watch(asideVisible, (newVal) => {
Object.keys(asideValue).forEach((key) => {
if (newVal[key] === false)
asideValue[key] = asideMap[key].defaultValue
})
})
if (newVal[key] === false) asideValue[key] = asideMap[key].defaultValue;
});
});
const asideEnter = ref(false)
const asideEnter = ref(false);
const showCollapse = computed(() => {
return collapse.value ? true : asideEnter.value
})
return collapse.value ? true : asideEnter.value;
});
const showSearch = ref(false)
const showSearch = ref(false);
function setShowSearch(value: boolean) {
showSearch.value = value
showSearch.value = value;
}
// key
function scrollHandler(key: string) {
const element = document.querySelector(`#${key}`)
element?.scrollIntoView(true)
const element = document.querySelector(`#${key}`);
element?.scrollIntoView(true);
}
function filterHandler(searchId: string) {
emitter.emit('filter-final', searchId)
emitter.emit("filter-final", searchId);
}
function editFilter(filter: any) {
const modal = unref(newFilterModalRef)! as any
modal.showModal()
modal.edit(filter)
const modal = unref(newFilterModalRef)! as any;
modal.showModal();
modal.edit(filter);
}
watch(asideValue, (newVal) => {
finalStore.setAsideValue(newVal)
})
finalStore.setAsideValue(newVal);
});
const inputChange = (keyword)=>{
}
const inputChange = (keyword) => {
console.log("Search Component", keyword);
emit("inputChange", keyword);
};
</script>
<template>
<div class="aside" :style="asideStyle" @mouseenter="asideEnter = true" @mouseleave="asideEnter = false">
<div
class="aside"
:style="asideStyle"
@mouseenter="asideEnter = true"
@mouseleave="asideEnter = false"
>
<div v-show="showCollapse" class="aside-collapse">
<div class="aside-collapse-btn" @click="collapseHandler">
<SvgIcon :name="collapseIcon" size="40" />
@ -165,23 +181,40 @@ const inputChange = (keyword)=>{
<n-scrollbar trigger="none">
<div class="aside-header">
<!-- 搜索跳转模块 -->
<Search v-show="showSearch" @select="scrollHandler" @close="setShowSearch(false)" @inputChange="inputChange" />
<Search
v-show="showSearch"
@select="scrollHandler"
@close="setShowSearch(false)"
@inputChange="inputChange"
/>
<!-- 高级筛选 -->
<AdvanceFilter
v-show="!showSearch" :type="1" @select="filterHandler" @update:search="setShowSearch(true)"
@show-custom="showModal(customModalRef)" @show-filter="showModal(filterModalRef)"
v-show="!showSearch"
:type="1"
@select="filterHandler"
@update:search="setShowSearch(true)"
@show-custom="showModal(customModalRef)"
@show-filter="showModal(filterModalRef)"
/>
</div>
<component
:is="item.config.component" v-for="(item, index) in showItems" :id="item.key" :key="index"
v-model:value="asideValue[item.key]" :label="item.config.label"
:is="item.config.component"
v-for="(item, index) in showItems"
:id="item.key"
:key="index"
v-model:value="asideValue[item.key]"
:label="item.config.label"
/>
<!-- 筛选 -->
<CustomFilterModalVue ref="customModalRef" />
<!-- 过滤列表 -->
<FilterModal ref="filterModalRef" @edit-filter="editFilter" @show-new-filter="showModal(newFilterModalRef)" />
<FilterModal
ref="filterModalRef"
@edit-filter="editFilter"
@show-new-filter="showModal(newFilterModalRef)"
/>
<!-- 新增过滤 -->
<NewFilterModal ref="newFilterModalRef" />
</n-scrollbar>
@ -193,7 +226,7 @@ const inputChange = (keyword)=>{
display: flex;
position: relative;
flex-direction: column;
background: #FFF;
background: #fff;
border: 1px solid #efeff5;
border-radius: 3px;
box-sizing: border-box;
@ -230,11 +263,17 @@ const inputChange = (keyword)=>{
right: -20px;
}
::v-deep(.n-collapse .n-collapse-item.n-collapse-item--right-arrow-placement .n-collapse-item__header .n-collapse-item-arrow) {
::v-deep(.n-collapse
.n-collapse-item.n-collapse-item--right-arrow-placement
.n-collapse-item__header
.n-collapse-item-arrow) {
margin-left: 8px;
}
::v-deep(.n-collapse .n-collapse-item .n-collapse-item__header .n-collapse-item__header-main) {
::v-deep(.n-collapse
.n-collapse-item
.n-collapse-item__header
.n-collapse-item__header-main) {
font-weight: bold;
justify-content: space-between;
}
@ -247,11 +286,18 @@ const inputChange = (keyword)=>{
border-top: 0px;
}
::v-deep(.n-collapse .n-collapse-item .n-collapse-item__content-wrapper .n-collapse-item__content-inner) {
::v-deep(.n-collapse
.n-collapse-item
.n-collapse-item__content-wrapper
.n-collapse-item__content-inner) {
padding-top: 10px;
}
::v-deep(.n-scrollbar > .n-scrollbar-rail.n-scrollbar-rail--vertical > .n-scrollbar-rail__scrollbar, .n-scrollbar + .n-scrollbar-rail.n-scrollbar-rail--vertical > .n-scrollbar-rail__scrollbar) {
::v-deep(.n-scrollbar
> .n-scrollbar-rail.n-scrollbar-rail--vertical
> .n-scrollbar-rail__scrollbar, .n-scrollbar
+ .n-scrollbar-rail.n-scrollbar-rail--vertical
> .n-scrollbar-rail__scrollbar) {
width: 0px;
}
}

@ -320,12 +320,15 @@ async function formatColumns() {
return h(SvgIcon, { name: 'sort-3' })
},
render(row: any) {
return h('div', {
id: row.id,
style: { color: row.similarityscore === 100 ? '#FF4E4F' : '' },
}, { default: () => row.similarityscore ? `${row.similarityscore}%` : '' })
return h(
'div',
{
id: row.id,
style: { color: row.similarityscore === 100 ? '#FF4E4F' : '' },
},
{ default: () => (row.similarityscore ? `${row.similarityscore}%` : '') },
)
},
}
}
index = columnsRef.value.findIndex(v => v.title == '提报时间')
@ -723,7 +726,9 @@ function doAudit(param: any) {
message.success(res.message)
reload()
}
else { message.error(res.message) }
else {
message.error(res.message)
}
})
},
onNegativeClick: () => {},
@ -760,6 +765,13 @@ async function refreshHandler(searchId?: any) {
reset()
query(pagination.page, pagination.pageSize, searchId)
}
function filterTableData(keyword) {
tableData.value = tableData.value.filter(item => item.id.includes(keyword))
}
defineExpose({
filterTableData,
})
</script>
<template>
@ -791,7 +803,12 @@ async function refreshHandler(searchId?: any) {
<img class="btn-approval btn-left" src="@/assets/images/task/btn-not-pass.png" alt="" @click.stop="batchReject">
<SvgIcon size="24" name="vs" />
<img class="btn-approval" src="@/assets/images/task/btn-pass.png" alt="" @click.stop="batchApproval">
<img
class="btn-approval"
src="@/assets/images/task/btn-pass.png"
alt=""
@click.stop="batchApproval"
>
</div>
<n-popover
@ -881,8 +898,8 @@ async function refreshHandler(searchId?: any) {
</template>
<style lang="less" scoped>
.color-red{
color: #FF4E4F!important;
.color-red {
color: #ff4e4f !important;
}
.batch {
@ -890,13 +907,13 @@ async function refreshHandler(searchId?: any) {
align-items: center;
margin-right: 10px;
.btn-approval{
.btn-approval {
width: 68px;
height: 28px;
cursor: pointer;
}
.btn-left{
.btn-left {
margin-left: 16px;
}
}
@ -937,7 +954,7 @@ async function refreshHandler(searchId?: any) {
.xjcc {
font-weight: bold;
color: #507AFD;
color: #507afd;
margin-right: 20px;
}

@ -7,7 +7,7 @@ import ListContent from './content/ListContent.vue'
const showList = ref(false);
const contentRef = ref(null);
const inputChange = (keyword)=>{
contentRef.value.filterTableData(keyword)
}
</script>

@ -233,6 +233,10 @@ function unFavoriteHandler(event: MouseEvent, item) {
}
}
const handleScroll= (event)=>{
console.log(event)
}
const moveEnd = () => {
unData.value.map((v, index) => {
sort(v.id, index);
@ -257,7 +261,12 @@ const moveEnd = () => {
<span style="font-size: 20px; color: #333333; font-weight: Medium">{{
currentlySelectedAdvanced
}}</span>
<SvgIcon :style="{ marginLeft: '5px' }" name="down" size="14" color="#999999"/>
<SvgIcon
:style="{ marginLeft: '5px' }"
name="down"
size="14"
color="#999999"
/>
</div>
</template>
<n-spin :show="loading">
@ -265,7 +274,7 @@ const moveEnd = () => {
<n-form :rules="rules" ref="ruleformRef" :model="ruleForm">
<n-form-item path="keyword">
<n-input
:style="{ '--n-border': '0px' }"
:style="{ '--n-border': '0px', '--n-display': 'block' }"
placeholder="请输入关键字"
@input="inputHandler"
:value="ruleForm.keyword"
@ -286,7 +295,7 @@ const moveEnd = () => {
</n-form-item>
</n-form>
<ul ref="el" class="wrapper-left-list">
<ul ref="el" class="wrapper-left-list" @scroll="handleScroll">
<li
v-for="(item, index) in data"
:key="index"
@ -429,4 +438,7 @@ const moveEnd = () => {
align-items: center;
}
}
::v-deep(.wrapper-left-popover .n-form-item){
display: block !important;
}
</style>

@ -40,6 +40,9 @@ onMounted(async () => {
Boolean(userFieldUnFixed?.find((v2) => v2 == v.name)),
};
offList.value.push(item);
if(item.checked){
selectIds.value.push(item.id);
}
});
});
@ -131,21 +134,18 @@ function onCheckAllChange(value) {
ids.push(item.id);
}
}
selectIds.value = value ? ids : [];
}
function onCheckChange(checked: any, item: any) {
const index = selectIds.value.indexOf(item.id);
item.checked = checked;
if (index === -1 && checked) selectIds.value.push(item.id);
else selectIds.value.splice(index, 1);
}
const indeterminate = computed(() => {
return offList.value.length > 0 && offList.value.length > selectIds.value.length;
return selectIds.value.length > 0 && offList.value.length > selectIds.value.length;
});
</script>

@ -1,14 +1,14 @@
<script lang="ts" setup>
import { deletePackage } from '@/api/home/main'
import NotPassed from '@/components/NotPassed.vue'
import { useWorkOrder } from '@/store/modules/workOrder'
import { isEmpty } from '@/utils'
import { useInfiniteScroll } from '@vueuse/core'
import { useMessage } from 'naive-ui'
import { reactive, ref, watch } from 'vue'
import ApprovalModal from '../modal/ApprovalModal.vue'
import ListItem from './ListItem.vue'
import type { PackageListItem } from '/#/workorder'
import { deletePackage } from "@/api/home/main";
import NotPassed from "@/components/NotPassed.vue";
import { useWorkOrder } from "@/store/modules/workOrder";
import { isEmpty } from "@/utils";
import { useInfiniteScroll } from "@vueuse/core";
import { useMessage } from "naive-ui";
import { reactive, ref, watch } from "vue";
import ApprovalModal from "../modal/ApprovalModal.vue";
import ListItem from "./ListItem.vue";
import type { PackageListItem } from "/#/workorder";
defineProps({
showFieldList: {
@ -19,132 +19,126 @@ defineProps({
type: Array,
default: () => [],
},
})
const workStore = useWorkOrder()
const data = ref<PackageListItem[]>([])
const activeId = ref('')
const el = ref<HTMLDivElement | null>(null)
const keyword = ref('')
const canloadMore = ref(true)
const isLoading = ref(false)
});
const workStore = useWorkOrder();
const data = ref<PackageListItem[]>([]);
const activeId = ref("");
const el = ref<HTMLDivElement | null>(null);
const keyword = ref("");
const canloadMore = ref(true);
const isLoading = ref(false);
const pagination = reactive({
pageNo: 0,
pageSize: 10,
})
});
const approvalModalRef: any = ref(null)
const notPassedRef: any = ref(null)
const approvalModalRef: any = ref(null);
const notPassedRef: any = ref(null);
const overTask = ref<any>(null);
function selectHandler(id: string, index: number) {
workStore.setActive(index)
// console.log('selectHandler',id)
workStore.setActive(index);
// showModal(approvalModalRef, id)
}
useInfiniteScroll(
el as any,
() => {
loadMore()
loadMore();
},
{
distance: 10,
interval: 1500,
canLoadMore: () => canloadMore.value,
},
)
}
);
async function loadMore() {
if (isLoading.value || el.value == null)
return
isLoading.value = true
if (isLoading.value || el.value == null) return;
isLoading.value = true;
try {
const more = await fetchList()
more.forEach(ele=>{
ele.search = JSON.parse(ele.search)
const more = await fetchList();
more.forEach((ele) => {
ele.search = JSON.parse(ele.search);
// ele.search.createTime = ele.search.submit_date_timestamp
})
data.value.push(...more)
}
finally {
isLoading.value = false
});
data.value.push(...more);
} finally {
isLoading.value = false;
}
}
async function fetchList() {
try {
pagination.pageNo += 1
const result = await workStore.fetchOrderList(pagination, keyword.value)
const { data, pageCount } = result
if (pageCount !== 0)
canloadMore.value = pageCount >= pagination.pageNo
else
canloadMore.value = false
return data || []
}
catch (error) {
canloadMore.value = false
return []
pagination.pageNo += 1;
const result = await workStore.fetchOrderList(pagination, keyword.value);
const { data, pageCount } = result;
if (pageCount !== 0) canloadMore.value = pageCount >= pagination.pageNo;
else canloadMore.value = false;
return data || [];
} catch (error) {
canloadMore.value = false;
return [];
}
}
watch(
() => workStore.activeId,
(newVal) => {
if (isEmpty(newVal))
return
if (isEmpty(newVal)) return;
activeId.value = newVal;
approvalModalRef.value.showModal(activeId.value)
},
)
approvalModalRef.value.showModal(workStore.dataId);
}
);
function reset() {
pagination.pageNo = 0
pagination.pageSize = 10
canloadMore.value = true
data.value.length = 0
pagination.pageNo = 0;
pagination.pageSize = 10;
canloadMore.value = true;
data.value.length = 0;
workStore.reset()
workStore.reset();
}
function notPass(value) {
notPassedRef.value.showModal(value)
notPassedRef.value.showModal(value);
}
async function search(word: string) {
keyword.value = word
reset()
keyword.value = word;
reset();
useInfiniteScroll(
el as any,
() => {
loadMore()
loadMore();
},
{ distance: 10, canLoadMore: () => canloadMore.value },
)
{ distance: 10, canLoadMore: () => canloadMore.value }
);
}
function overTaskHandelr(item: any) {
overTask.value = item
overTask.value = item;
}
function leaveTaskHandler(event) {
if(event?.relatedTarget?.id !=="taskPopconfirmRef"){
if (event?.relatedTarget?.id !== "taskPopconfirmRef") {
overTask.value = null;
}
}
const message = useMessage()
function dismisClick(packageId:string) {
deletePackage({packageId: packageId}).then((res) => {
if(res.code==="OK"){
message.success("解散任务包成功")
reset()
loadMore()
const message = useMessage();
function dismisClick(packageId: string) {
deletePackage({ packageId: packageId }).then((res) => {
if (res.code === "OK") {
message.success("解散任务包成功");
reset();
loadMore();
}
})
});
}
defineExpose({
search,
})
});
</script>
<template>
@ -161,7 +155,7 @@ defineExpose({
:dicts="dicts"
:mouse-over-task="overTask"
@click="selectHandler(item.id, index)"
@mouseover="overTaskHandelr(item)"
@mouseover="overTaskHandelr(item)"
@mouseleave="leaveTaskHandler"
@dismisClick="dismisClick"
/>

@ -0,0 +1,183 @@
<script setup lang="ts">
import { fieldMap } from "@/config/workorder";
import { TASK_STATUS_OBJ } from '@/enums/index';
import { format } from 'date-fns';
import { pickBy } from "lodash-es";
import { computed, defineProps } from "vue";
const props = defineProps({
taskDetailInfo: {
type: Object,
default: () => ({}),
},
});
const propertys = computed(() => {
const { ocrPicture } = props.taskDetailInfo;
const v = pickBy(ocrPicture, (value, key: string) => {
return key.startsWith("field") && value !== null;
});
return v;
});
</script>
<template>
<div class="right">
<n-scrollbar style="max-height: 100%">
<n-ellipsis style="max-width: 350px">任务ID{{ taskDetailInfo.taskname }}</n-ellipsis>
<div class="tags">
<div class="tag tag-submiting" v-if="taskDetailInfo.historyStates == '1'"></div>
<div class="tag tag-submited" v-else-if="taskDetailInfo.historyStates == 2 || taskDetailInfo.workStatus == 3">已审批</div>
<div class="tag tag-passed" v-if="taskDetailInfo.historyStates == 2">{{ TASK_STATUS_OBJ[taskDetailInfo.historyStates] }}</div>
<div class="tag tag-not-passed" v-else-if="taskDetailInfo.workStatus == 3">{{ TASK_STATUS_OBJ[taskDetailInfo.historyStates] }}</div>
</div>
<n-divider class="divider-line" />
<div class="property">
<span class="property-name top" style="color: #666666">图片大小</span>
<span style="color: #333333; font-size: 16px">{{ taskDetailInfo?.pictureInfo?.imgSize && (taskDetailInfo.pictureInfo.imgSize / 1000).toFixed(2) }}KB</span>
</div>
<div class="property">
<span class="property-name top" style="color: #666666">图片格式</span>
<span style="color: #333333; font-size: 16px">{{ taskDetailInfo?.pictureInfo?.imgFormat }}</span>
</div>
<div class="property">
<span class="property-name top" style="color: #666666">图片尺寸</span>
<span style="color: #333333; font-size: 16px">{{ taskDetailInfo?.pictureInfo?.imgMeasure }}</span>
</div>
<div class="property">
<span class="property-name top" style="color: #666666">色彩空间</span>
<span style="color: #333333; font-size: 16px">{{ taskDetailInfo?.pictureInfo?.imgSpace }}</span>
</div>
<div class="property">
<span class="property-name top" style="color: #666666">提报人</span>
<span style="color: #333333; font-size: 16px">{{ taskDetailInfo?.upname || "-" }}</span>
</div>
<div class="property">
<span class="property-name top" style="color: #666666">创建时间</span>
<span style="color: #333333; font-size: 16px">{{ taskDetailInfo?.pictureInfo?.createTime }}</span>
</div>
<div class="property">
<span class="property-name top" style="color: #666666">提报时间</span>
<span style="color: #333333; font-size: 16px">{{ taskDetailInfo?.submitDateTimestamp && format(taskDetailInfo.submitDateTimestamp, 'yyyy-MM-dd HH:mm:ss') || '-' }}</span>
</div>
<div v-for="(value, key) in propertys" :key="key" class="property">
<span class="property-name">{{ fieldMap[key] }}</span>
<span class="property-content">{{ value }}</span>
</div>
</n-scrollbar>
</div>
</template>
<style lang="less" scoped>
.right {
// flex: 1;
// display: flex;
// flex-direction: column;
// justify-content: space-between;
// // background: #fafafa;
// border-radius: 8px;
// margin-left: 20px;
// padding: 24px;
// width: 24vw;
flex: 0.5;
background: #f9f9f9;
border-radius: 8px;
margin-left: 20px;
padding: 24px;
// background: lime;
.task-name {
display: inline-block;
width: 100%;
font-size: 18px;
color: #0d0b22;
line-height: 25px;
font-family: PingFang SC, PingFang SC-Medium;
font-weight: Medium;
max-width: 445px;
/* 设置文本溢出时的样式为省略号 */
text-overflow: ellipsis;
/* 隐藏超出容器的文本 */
overflow: hidden;
/* 确保文本不换行 */
white-space: nowrap;
}
// ::v-deep(.n-divider:not(.n-divider--vertical)) {
::v-deep(.divider-line .n-divider__line) {
background-color: #e8e8e8;
}
.tags {
display: flex;
margin-top: 8px;
}
.tag {
border: 1px solid #d8d8d8;
box-sizing: border-box;
border-radius: 8px;
color: #666666;
margin-right: 12px;
padding: 4px 8px;
font-size: 12px;
line-height: 16px;
}
.tag-submited {
color: #507AFD;
border: 1px solid #507AFD;
}
.tag-submiting {
color: #FFB800;
border: 1px solid #FFB800;
}
.tag-passed {
color: #02C984;
border: 1px solid #02C984;
}
.tag-not-passed {
color: #ff7575;
border: 1px solid #ff7575;
}
.tag-approved {
color: #507afd;
border: 1px solid #507afd;
}
.property {
display: flex;
align-items: center;
margin-top: 12px;
line-height: 20px;
}
.property-name {
width: 56px;
text-align: right;
color: #999999;
position: relative;
margin-right: 32px;
}
.top {}
.property-content {
flex: 1;
color: #333333;
}
}
::v-deep(.n-divider:not(.n-divider--vertical)) {
margin-top: 12px;
margin-bottom: 12px;
}
</style>

@ -1,11 +1,9 @@
<script lang="ts" setup>
import { audit } from '@/api/task/task';
import {
getTaskDetailInfo,
getTaskDetailPictureList
getPictureSimilarityList, getTaskDetailInfo
} from "@/api/work/work";
import NotPassed from '@/components/Approval/NotPassed.vue';
import { fieldMap } from "@/config/workorder";
import { TASK_STATUS_OBJ } from '@/enums/index';
import { useWorkOrder } from "@/store/modules/workOrder";
import { isEmpty } from "@/utils";
@ -18,6 +16,7 @@ import imagesloaded from "imagesloaded";
import { clone, debounce, pickBy } from "lodash-es";
import { useDialog, useMessage } from "naive-ui";
import { computed, onUnmounted, onUpdated, reactive, ref, unref, watch } from "vue";
import PictureInfo from "../components/PictureInfo.vue";
import ConfrimModal from "../modal/ConfrimModal.vue";
import type { ApprovalParam, SimilarityPictureSortParam } from "/#/api";
@ -135,7 +134,7 @@ async function featchList() {
loading.value = true;
try {
taskpagination.pageNo += 1;
const { data, total, pageCount } = await getTaskDetailPictureList(
const { data, total, pageCount } = await getPictureSimilarityList(
{ ...taskpagination, ...sortBy, checkDuplicateId: workStore.activeId, pictureId: taskDetailInfo.value.id }
);
@ -487,18 +486,10 @@ function reloadList() {
</div>
</div>
<!-- 右侧任务 标题信息 -->
<div class="right">
<!-- <div class="right">
<n-scrollbar style="max-height: 100%">
<n-ellipsis style="max-width: 350px">任务ID{{ taskDetailInfo.taskname }}</n-ellipsis>
<div class="tags">
<!-- <div class="tag tag-submiting" v-if="taskDetailInfo.workStatus == '1'">{{ TASK_STATUS_OBJ[taskDetailInfo.workStatus]
}}</div>
<div class="tag tag-submited" v-else-if="taskDetailInfo.workStatus == '2'">已审批</div>
<div class="tag tag-passed" v-if="taskDetailInfo.historyStates == 2">{{
TASK_STATUS_OBJ[taskDetailInfo.historyStates] }}</div>
<div class="tag tag-not-passed" v-else-if="taskDetailInfo.workStatus == 3">{{
TASK_STATUS_OBJ[taskDetailInfo.historyStates]
}}</div> -->
<div class="tag tag-submiting" v-if="taskDetailInfo.historyStates == '1'"></div>
<div class="tag tag-submited" v-else-if="taskDetailInfo.historyStates == 2 || taskDetailInfo.workStatus == 3">已审批</div>
<div class="tag tag-passed" v-if="taskDetailInfo.historyStates == 2">{{
@ -550,7 +541,8 @@ function reloadList() {
<span class="property-content">{{ propertys[key] }}</span>
</div>
</n-scrollbar>
</div>
</div> -->
<PictureInfo :taskDetailInfo="taskDetailInfo"></PictureInfo>
</div>
<div style="display: flex; justify-content: space-between; padding: 12px 0px 3px 0">
<div>
@ -607,11 +599,6 @@ function reloadList() {
<div class="pass-status" v-else-if="item.historyStates === 3">
<SvgIcon name="no-pass-icon" style="width:52;height:24px" />
</div>
<!--
重复标签
<div class="pass-status" v-if="item.historyStates === 1">
<SvgIcon name="repeat-icon" style="width:52;height:24px" />
</div> -->
<div v-show="overTask && overTask.id === item.id" class="action">
<SvgIcon style="cursor: pointer" name="t1" @click.stop="approvalHandler" />
<SvgIcon style="cursor: pointer;margin-left: 40px;" name="t2" @click.stop="singleRejectHandler(item)" />
@ -675,29 +662,6 @@ function reloadList() {
}
}
.right {
display: flex;
align-items: center;
.btn {
width: 118px;
height: 36px;
background: linear-gradient(135deg, #5b85f8, #3c6cf0);
border-radius: 17px;
box-shadow: 0px 2px 6px 0px rgba(116, 153, 253, 0.3);
display: flex;
align-items: center;
justify-content: center;
color: #fff;
cursor: pointer;
}
.batch {
display: flex;
align-items: center;
}
}
.font {
font-size: 20px;
font-family: PingFang SC, PingFang SC-Medium;

@ -3,6 +3,7 @@ import { nextTick, onDeactivated, onMounted, reactive, ref, toRefs } from "vue";
import { format } from "date-fns";
import { NButton, NDataTable, useDialog, useMessage } from "naive-ui";
import { aiApprovaltools, aiApprovaltoolsClearmark, setTF } from "@/api/work/work";
import { audit } from "@/api/task/task";
import { getToolsCount } from "@/api/home/main";
import { storage } from "@/utils/Storage";
import { CURRENT_USER } from "@/store/mutation-types";
@ -10,6 +11,7 @@ const emit = defineEmits<{
(e: "reject", params: any);
(e: "notPass", params: any);
}>();
const message = useMessage()
const dialog = useDialog();
@ -34,21 +36,33 @@ function showModal(id) {
async function getDetail(id) {
// const userInfo = storage.get(CURRENT_USER);
// const nodeType = userInfo.nodeType;
// id = "264626184091111068";
// id = "264627119490116380";
const res = await aiApprovaltools({ taskid: id });
if (res.code === "OK") {
state.detail = res.data;
show.value = true;
if(Number(res.data.pendingApprovaCount) > 0){
show.value = true;
}
}
}
const handleReject = async () => {
const res = await setTF({
taskchildpictureids: state.detail.taskIdList.join(","),
packageid: state.packageid,
iztrueorfalse: 0,
});
console.log(res, "handleReject");
const param = {
result: false,
comment: '',
disposeType: '',
disposeTypeId: '',
failCauseId: '',
failCauseName: '',
flowTaskInfoList: state.detail.flowTaskInfoList,
}
const res = await audit(param)
if(res.code == 'OK'){
message.success(res.message)
}else{
message.error(res.message)
}
closeModal();
};
async function clearMark() {
@ -86,13 +100,6 @@ async function viewRepeat(e: MouseEvent) {
closeModal();
}
async function getShowStatus() {
const res = await getToolsCount();
if (res.code == "OK") {
show.value = true;
}
}
const initRem = () => {
const designWidth = 1440;
const rempPx = 16;
@ -100,7 +107,6 @@ const initRem = () => {
document.documentElement.style.fontSize = scale * rempPx + "px";
};
onMounted(() => {
getShowStatus();
nextTick(() => {
initRem();
});
@ -126,7 +132,7 @@ defineExpose({
<div class="wrapper-hearder">
<div class="wrapper-title">智能AI审批工具</div>
<div class="wrapper-mark">
{{ detail.tenantUserName || '部门信息' }}
{{ detail.tenantUserName || "部门信息" }}
</div>
</div>
<div class="wrapper-content">
@ -143,7 +149,7 @@ defineExpose({
</div>
<div class="time_box">
任务包生成时间
{{ format(detail?.createtime || 0, "yyyy-MM-dd HH:mm:ss") }}
{{ format(detail?.createTime || 0, "yyyy-MM-dd HH:mm:ss") }}
</div>
</div>
</div>

@ -17,7 +17,8 @@ export interface OrderState {
currentIndex: number
packageList: PackageListItem[]
approvalList: any[]
immersion: boolean
immersion: boolean,
dataId: string
}
// 任务实体

Loading…
Cancel
Save