Merge branch 'main' into al

bak
刘释隆 1 year ago
commit df2fec3107

@ -1,5 +1,5 @@
import { http } from '@/utils/http/axios'
import type { PageParam } from '/#/api'
import type { BusinessParam, PageParam } from '/#/api'
/**
*
@ -315,3 +315,23 @@ export async function getBackList() {
const list = res.data
return list
}
/**
*
* @returns
*/
export async function getBusinessList(field: string, page: PageParam = { pageNo: 1, pageSize: 200 }) {
const res = await http.request({
url: `/ocr/dictionary/getDictionaryByField`,
method: 'get',
params: { ...page, field },
})
const { otherMessage: { records } } = res
return records.map((record) => {
return {
label: record.lable || 'todo',
value: record.value || 'todo',
}
})
}

@ -65,10 +65,11 @@ export async function deleteCondition(params: { ids: string }) {
*
* @returns
*/
export async function getFilter(): Promise<any> {
export async function getFilter(type: number): Promise<any> {
return http.request({
url: `/ocr/ocrSearchmanager/query`,
method: 'get',
params: { type },
})
}

@ -42,3 +42,14 @@ export async function forgetPassword(params: any) {
params,
})
}
/**
*
*/
export async function updateSUser(params: any) {
return http.request({
url: `/ocr/sUser/updateSUser`,
method: 'post',
params,
})
}

@ -1,11 +1,10 @@
import { http } from '@/utils/http/axios'
import type { PageParam, PictureSortParam, SetTFParam } from '/#/api'
/**
*
* @returns
*/
export async function getMessageList(params: PageParam) {
export async function getMessageList(params) {
const res = await http.request({
url: `/ocr/msg/systemPage`,
method: 'get',
@ -14,3 +13,45 @@ export async function getMessageList(params: PageParam) {
return res
}
/**
*
* @returns
*/
export async function msgOne(params) {
const res = await http.request({
url: `/ocr/msg/msgOne`,
method: 'get',
params,
})
return res
}
/**
*
* @returns
*/
export async function readMsg(params) {
const res = await http.request({
url: `/ocr/msg/eliminateUnreadone`,
method: 'post',
params,
})
return res
}
/**
*
* @returns
*/
export async function readAllMsg(params) {
const res = await http.request({
url: `/ocr/msg/eliminateUnreadfull`,
method: 'post',
params,
})
return res
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

@ -0,0 +1,52 @@
export const asideMap: Recordable<AsideEntity> = {
izupuser: {
label: '',
defaultValue: null,
isDefaultFilter: true,
key: 'izupuser',
component: ReportUserVue,
},
izproject: {
label: '',
defaultValue: null,
isDefaultFilter: true,
key: 'izproject',
component: IzProjectVue,
},
izplan: {
label: '',
defaultValue: null,
isDefaultFilter: true,
key: 'izplan',
component: PlanVue,
},
izstatus: {
label: '',
defaultValue: null,
isDefaultFilter: false,
key: 'izstatus',
component: PlanVue, // todo
},
izuptime: {
label: '',
defaultValue: null,
isDefaultFilter: false,
key: 'izuptime',
component: TimeVue,
},
iztaskrrom: {
label: '',
defaultValue: null,
isDefaultFilter: false,
key: 'iztaskrrom',
component: IztaskrromVue,
},
izshowall: {
label: '',
defaultValue: true,
isDefaultFilter: false,
key: 'izshowall',
component: PictureDownloadVue,
inFilterList: false,
},
}

@ -42,13 +42,13 @@ export const asideMap: Recordable<AsideEntity> = {
key: 'izplan',
component: PlanVue,
},
// izsimilarity: {
// label: '相似度阈值',
// defaultValue: [0,100],
// isDefaultFilter: false,
// key: 'izsimilarity',
// component: SimilarityVue,
// },
izsimilarity: {
label: '相似度阈值',
defaultValue: [0, 100],
isDefaultFilter: false,
key: 'izsimilarity',
component: SimilarityVue,
},
izyear: {
label: '年份',
defaultValue: null,

@ -1,3 +1,6 @@
import type { AsideEntity } from './aside'
import { IzProjectVue, IztaskrromVue, PictureDownloadVue, PlanVue, ReportUserVue, TimeVue } from '@/views/home/aside/comp/items'
export interface RowData {
id: string
fromtaskname: string
@ -72,3 +75,57 @@ export function findKey(columns: any[], header: string) {
const item = columns.find((column) => { return (column as any).title === header })
return (item as any).key
}
// 终审左侧配置
export const asideMap: Recordable<AsideEntity> = {
izupuser: {
label: '提报人',
defaultValue: null,
isDefaultFilter: true,
key: 'izupuser',
component: ReportUserVue,
},
izproject: {
label: '所属项目',
defaultValue: null,
isDefaultFilter: true,
key: 'izproject',
component: IzProjectVue,
},
izplan: {
label: '所属计划',
defaultValue: null,
isDefaultFilter: true,
key: 'izplan',
component: PlanVue,
},
izstatus: {
label: '审批状态',
defaultValue: null,
isDefaultFilter: false,
key: 'izstatus',
component: PlanVue, // todo
},
izuptime: {
label: '提报时间',
defaultValue: null,
isDefaultFilter: false,
key: 'izuptime',
component: TimeVue,
},
iztaskrrom: {
label: '任务来源',
defaultValue: null,
isDefaultFilter: false,
key: 'iztaskrrom',
component: IztaskrromVue,
},
izshowall: {
label: '显示全部任务数据',
defaultValue: true,
isDefaultFilter: false,
key: 'izshowall',
component: PictureDownloadVue,
inFilterList: false,
},
}

@ -1,17 +1,17 @@
<script lang="ts">
import { useUser } from "@/store/modules/user";
import { getImgUrl } from "@/utils/urlUtils";
import { useDialog, useMessage } from "naive-ui";
import { defineComponent, reactive, ref, toRefs, unref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import QuillModal from "./QuillModal.vue";
import RecycleModal from "./RecycleModal.vue";
import SearchModal from "./SearchModal.vue";
import ShortcutModal from "./ShortcutModal.vue";
import UserSettings from "./UserSettings.vue";
import { useDialog, useMessage } from 'naive-ui'
import { defineComponent, reactive, ref, toRefs, unref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import QuillModal from './QuillModal.vue'
import RecycleModal from './RecycleModal.vue'
import SearchModal from './SearchModal.vue'
import ShortcutModal from './ShortcutModal.vue'
import UserSettings from './UserSettings.vue'
import { getImgUrl } from '@/utils/urlUtils'
import { useUser } from '@/store/modules/user'
export default defineComponent({
name: "PageHeader",
name: 'PageHeader',
components: {
UserSettings,
QuillModal,
@ -27,108 +27,112 @@ export default defineComponent({
type: Boolean,
},
},
emits: ["update:collapsed"],
emits: ['update:collapsed'],
setup() {
const message = useMessage();
const dialog = useDialog();
const message = useMessage()
const dialog = useDialog()
const userStore = useUser();
const useInfo = userStore.getUserInfo;
const userStore = useUser()
const useInfo = userStore.getUserInfo
const name = "";
const name = ''
const state = reactive({
username: name ?? "",
fullscreenIcon: "FullscreenOutlined",
});
username: name ?? '',
fullscreenIcon: 'FullscreenOutlined',
})
const router = useRouter();
const route = useRoute();
const routename = ref(route.meta.title);
const router = useRouter()
const route = useRoute()
const routename = ref(route.meta.title)
watch(
() => route.fullPath,
() => {
routename.value = route.meta.title;
}
);
routename.value = route.meta.title
},
)
const dropdownSelect = (key) => {
router.push({ name: key });
};
router.push({ name: key })
}
// 退
const doLogout = () => {
dialog.info({
title: "提示",
content: "您确定要退出登录吗",
positiveText: "确定",
negativeText: "取消",
title: '提示',
content: '您确定要退出登录吗',
positiveText: '确定',
negativeText: '取消',
onPositiveClick: () => {
userStore.logout().then(() => {
message.success("成功退出登录");
message.success('成功退出登录')
router
.replace({
name: "Login",
name: 'Login',
query: {
redirect: route.fullPath,
},
})
.finally(() => location.reload());
});
.finally(() => location.reload())
})
},
onNegativeClick: () => {},
});
};
})
}
const quillModalRef = ref(null);
const shortcutModal = ref(null);
const recycleModalRef = ref(null);
const SearchModalRef = ref(null);
const quillModalRef = ref(null)
const shortcutModal = ref(null)
const recycleModalRef = ref(null)
const SearchModalRef = ref(null)
function quillHandler() {
const modal = unref(quillModalRef)! as any;
modal.showModal();
const modal = unref(quillModalRef)! as any
modal.showModal()
}
function shortcutHandler() {
const modal = unref(shortcutModal)! as any;
modal.showModal();
const modal = unref(shortcutModal)! as any
modal.showModal()
}
function recycleHandler() {
const modal = unref(recycleModalRef)! as any;
modal.showModal();
const modal = unref(recycleModalRef)! as any
modal.showModal()
}
function searchHandler() {
const modal = unref(SearchModalRef)! as any;
modal.showModal();
const modal = unref(SearchModalRef)! as any
modal.showModal()
}
function goMessage() {
router.push({ name: 'message-main' })
}
//
const iconList = [
{
icon: "magnifying-1",
icon: 'magnifying-1',
handle: searchHandler,
},
{
icon: "shortcut-keys",
icon: 'shortcut-keys',
handle: shortcutHandler,
},
{
icon: "suspicious-folder",
icon: 'suspicious-folder',
handle: recycleHandler,
},
{
icon: "memo",
icon: 'memo',
handle: quillHandler,
},
{
icon: "newmessage",
handle: shortcutHandler,
icon: 'newmessage',
handle: goMessage,
},
];
]
return {
...toRefs(state),
@ -146,9 +150,9 @@ export default defineComponent({
recycleHandler,
useInfo,
getImgUrl,
};
}
},
});
})
</script>
<template>

@ -23,8 +23,9 @@ const routes: Array<RouteRecordRaw> = [
permissions: ['worksheet-main'],
svgname: 'worksheet',
svgsize: 22,
sort: 2,
sort: 5,
disabled: true,
hidden: true,
},
children: [
{

@ -7,7 +7,7 @@ import type { AsideConfig } from '/#/api'
export interface ConfigState {
systemConfig: AsideConfig | null
customConfig: any
customConfig: string[] | null
asideValue: any
}
@ -22,7 +22,7 @@ export const useAsideConfigStore = defineStore({
getConfig(): AsideConfig | null {
return this.systemConfig
},
getCustomConfig(): any {
getCustomConfig(): string[] | null {
return this.customConfig
},
getAsideValue(): any {
@ -33,9 +33,6 @@ export const useAsideConfigStore = defineStore({
setConfig(config: AsideConfig) {
this.systemConfig = config
},
setCustomConfig(config: any) {
this.customConfig = config
},
setAsideValue(value) {
this.asideValue = value
},
@ -47,9 +44,11 @@ export const useAsideConfigStore = defineStore({
},
// 获取个性化配置
async fetchCustomConfig() {
const response = await getFilter()
this.setCustomConfig(response.data)
return response.data
const res = await getFilter(0)
const { data } = res
const list = data && data.searchcount ? data.searchcount.split(',') : []
this.customConfig = list
return list
},
},
})

@ -1,6 +1,6 @@
import { defineStore } from 'pinia'
import { store } from '@/store'
import { getBackList, getIzCustomtypeList, getIzProjectList, getIzShowList, getIzcustomlevel, getIzfirmList, getIzproductnameList, getIzprojecttypeList, getIztaskrromList, getIztaskstatusList, getIzvisitcityList, getIzvisitproList, getPersonList, getPictureTypeList, getPlanList, getRegionList, getRejectList, getTFList, getizcustomnameList } from '@/api/dictionary'
import { getBackList, getBusinessList, getIzShowList, getPictureTypeList, getRegionList, getRejectList, getTFList } from '@/api/dictionary'
export interface DictionaryState {
regionList: any
@ -112,14 +112,14 @@ export const useDictionaryStore = defineStore({
},
// 获取提报人列表
async fetchPersionList() {
const list = await getPersonList()
this.personList = generateOptions(list, 'id', 'upname')
const list = await getBusinessList('person')
this.personList = list
return this.personList
},
// 获取计划列表
async fetchPlanList() {
const list = await getPlanList()
this.planList = generateOptions(list, 'id', 'planname')
const list = await getBusinessList('plan')
this.planList = list
return this.planList
},
// 获取图片真假原因
@ -134,59 +134,70 @@ export const useDictionaryStore = defineStore({
this.izShowList = generateOptions2(list, 'id', 'classname')
return this.izShowList
},
// 所属项目
async fetchIzProjectList() {
const list = await getIzProjectList()
this.izProjectList = generateOptions(list, 'id', 'categoryname')
const list = await getBusinessList('project')
this.izProjectList = list
return this.izProjectList
},
// 任务来源
async fetchIztaskrromList() {
const list = await getIztaskrromList('1')
this.izCustomtypeList = generateOptions(list)
return this.izCustomtypeList
const list = await getBusinessList('iztaskrrom')
this.iztaskrromList = list
return this.iztaskrromList
},
// 任务状态
async fetchIztaskstatusList() {
const list = await getIztaskstatusList('1')
this.iztaskstatusList = generateOptions(list)
const list = await getBusinessList('iztaskstatus')
this.iztaskstatusList = list
return this.iztaskstatusList
},
// 地区(省信息)
async fetchIzvisitproList() {
const list = await getIzvisitproList()
this.izvisitproList = generateOptions(list, 'id', 'proname')
const list = await getBusinessList('izvisitpro')
this.izvisitproList = list
return this.izvisitproList
},
// 厂商
async fetchIzfirmList() {
const list = await getIzfirmList('1')
this.izfirmList = generateOptions(list)
const list = await getBusinessList('izfirm')
this.izfirmList = list
return this.izfirmList
},
// 产品名称
async fetchIzproductnameList() {
const list = await getIzproductnameList('1')
this.izproductnameList = generateOptions(list)
const list = await getBusinessList('izproductname')
this.izproductnameList = list
return this.izproductnameList
},
// 客户名称
async fetchizcustomnameList() {
const list = await getizcustomnameList('1')
this.izcustomnameList = generateOptions(list)
const list = await getBusinessList('izcustomname')
this.izcustomnameList = list
return this.izcustomnameList
},
// 客户类型
async fetchIzCustomtypeList() {
const list = await getIzCustomtypeList()
this.izCustomtypeList = generateOptions(list)
const list = await getBusinessList('izcustomtype')
this.izCustomtypeList = list
return this.izCustomtypeList
},
// 客户级别
async fetchIzcustomlevelList() {
const list = await getIzcustomlevel('1')
this.izcustomlevelList = generateOptions(list)
const list = await getBusinessList('izcustomlevel')
this.izcustomlevelList = list
return this.izcustomlevelList
},
// 项目类别
async fetchizizprojecttypeList() {
const list = await getIzprojecttypeList('1')
this.izizprojecttypeList = generateOptions(list)
const list = await getBusinessList('izprojecttype')
this.izizprojecttypeList = list
return this.izizprojecttypeList
},
// 发布地区
async fetchizvisitcityList() {
const list = await getIzvisitcityList()
this.izvisitcityList = generateOptions(list)
const list = await getBusinessList('izvisitcity')
this.izvisitcityList = list
return this.izvisitcityList
},
async fetchRejectList() {

@ -0,0 +1,42 @@
import { defineStore } from 'pinia'
import { store } from '@/store'
import { getFilter } from '@/api/home/filter'
export interface ConfigState {
customConfig: string[] | null
asideValue: any
}
export const useFinalStore = defineStore({
id: 'app-final',
state: (): ConfigState => ({
customConfig: null,
asideValue: null,
}),
getters: {
getCustomConfig(): string[] | null {
return this.customConfig
},
getAsideValue(): any {
return this.asideValue
},
},
actions: {
setAsideValue(value) {
this.asideValue = value
},
// 获取终审个性化配置
async fetchCustomConfig() {
const res = await getFilter(1)
const { data } = res
const list = data && data.searchcount ? data.searchcount.split(',') : []
this.customConfig = list
return list
},
},
})
// Need to be used outside the setup
export function useFinal() {
return useFinalStore(store)
}

@ -45,15 +45,15 @@ export const useTaskStore = defineStore({
},
async fetchApprovalList(pagination, id, refresh?: boolean) {
const res = await getApprovalList(pagination, id)
this.setApprovalList(res.data)
if (res.data.length > 0) {
this.setApprovalList(res.data)
this.setActive(0)
// 审批操作完成后需要刷新为防止activeId在刷新后值不变通过此值刷新
this.refresh = !this.refresh
}
return res.data
return res
},
updateImmersion() {
this.immersion = !this.immersion

@ -1,21 +1,21 @@
<script lang="ts" setup>
import { computed, nextTick, onBeforeMount, onMounted, reactive, ref, shallowRef, unref, watch } from 'vue'
import { CustomFilterModalVue, FilterModalVue, NewFilterModalVue } from '@/views/home/aside/comp/modals'
import { CustomFilterModalVue } 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 { useConfig } from '@/store/modules/asideConfig'
import { useFinal } from '@/store/modules/final'
import type { Filter } from '/#/home'
import type { AsideEntity } from '@/config/aside'
import { asideMap } from '@/config/aside'
import { asideMap } from '@/config/final'
import type { AsideConfig } from '/#/api'
const configStore = useConfig()
const finalStore = useFinal()
//
const asideValue: Record<keyof typeof asideMap, any> = reactive({})
// :
// :
const asideVisible: Partial<Record<keyof AsideConfig, boolean>> = reactive({})
//
const showItems = shallowRef<{ key: string, config: AsideEntity }[]>([])
@ -73,32 +73,37 @@ function computeSlideHeight() {
useWindowSizeFn(computeSlideHeight, 280)
onBeforeMount(async () => {
configStore.fetchConfig()
configStore.fetchCustomConfig()
finalStore.fetchCustomConfig()
})
configStore.$subscribe(() => {
const config = configStore.getConfig
const customConfig = configStore.getCustomConfig
finalStore.$subscribe(() => {
const customConfig = finalStore.getCustomConfig
if (config === null || customConfig === null)
if (customConfig === null)
return
const showKeys = customConfig.searchcount.split(',')
const showKeys: string[] = [...customConfig]
const defaultKeys = Object.keys(asideMap).filter(key => asideMap[key].isDefaultFilter)
showKeys.unshift(...defaultKeys)
Object.keys(config).forEach((key) => {
Object.keys(asideMap).forEach((key) => {
//
if (key.startsWith('iz'))
asideVisible[key] = showKeys.includes(key) && config[key] === 'Y'
asideVisible[key] = asideMap[key] && (showKeys.includes(key) || asideMap[key].isDefaultFilter)
})
const items = showKeys.map((key: string) => {
const str = key.toLowerCase()
return {
key: str,
config: asideMap[str],
const items = showKeys.reduce((acc, key) => {
if (asideMap[key]) {
const config = {
key,
config: asideMap[key],
}
return [...acc, config]
}
})
else {
return acc
}
}, [])
showItems.value = items
})
@ -137,12 +142,7 @@ function filterHandler(filterList: Filter[]) {
filerMap[key] = value
}
Object.keys(asideValue).forEach((key) => {
if (Object.prototype.hasOwnProperty.call(filerMap, key))
asideValue[key] = filerMap[key]
else
asideValue[key] = asideMap[key].defaultValue
})
// TODO:
}
function editFilter(filter: any) {
@ -152,7 +152,7 @@ function editFilter(filter: any) {
}
watch(asideValue, (newVal) => {
configStore.setAsideValue(newVal)
finalStore.setAsideValue(newVal)
})
</script>
@ -179,10 +179,6 @@ watch(asideValue, (newVal) => {
v-model:value="asideValue[item.key]" :label="item.config.label"
/>
<!-- 过滤列表 -->
<FilterModalVue ref="filterModalRef" @edit-filter="editFilter" @show-new-filter="showModal(newFilterModalRef)" />
<!-- 新增过滤 -->
<NewFilterModalVue ref="newFilterModalRef" />
<!-- 筛选 -->
<CustomFilterModalVue ref="customModalRef" />
</n-scrollbar>
@ -217,7 +213,7 @@ watch(asideValue, (newVal) => {
height: 100%;
background: #507afd;
position: absolute;
right: 0;
right: -2px;
top: 0;
z-index: 18;
}

@ -1,8 +1,23 @@
<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import { difference } from 'lodash-es'
import { VueDraggable } from 'vue-draggable-plus'
import { workPackageMap } from '@/config/workorder'
import { debounce, difference } from 'lodash-es'
import { setFilter } from '@/api/home/filter'
import { asideMap } from '@/config/final'
import { useFinal } from '@/store/modules/final'
const show = ref(false)
const checkAll = ref(false)
const selectIds = ref<string[]>([])
const finalStore = useFinal()
function showModal() {
show.value = true
}
function closeModal() {
show.value = false
}
//
const offList = ref<any[]>([])
@ -17,57 +32,65 @@ const selectCount = computed(() => {
return `全部筛选(共${onList.value.length}个)`
})
function generatList() {
const keys = Object.keys(workPackageMap)
let showList: object[] = []
const hideList: object[] = []
const showStr = 'status'
const showKeys = showStr.split(',').map((key: string) => key.toLowerCase())
defineExpose({
showModal,
})
for (const key of keys) {
const name = workPackageMap[key]?.label
const isDefault = workPackageMap[key]?.isDefault
function generateDefaultList() {
return Object.keys(asideMap).reduce((acc, key) => {
const { label, isDefaultFilter } = asideMap[key]
// Y
if (!isDefault) {
hideList.push({
//
if (isDefaultFilter) {
const config = {
id: key,
name: name || '未配置',
fix: isDefault,
checked: workPackageMap[key].isDefault,
})
name: label || '未配置',
fix: isDefaultFilter,
checked: true,
}
return [...acc, config]
}
}
showList = showKeys.reduce((acc, key) => {
const config = {
id: key,
name: workPackageMap[key].label || '未配置',
fix: workPackageMap[key].isDefault,
else {
return acc
}
return [...acc, config]
}, [])
}
const fixedList = generateDefaultList()
function generatList(customConfig) {
const keys = Object.keys(asideMap)
let onList: object[] = []
const offList: object[] = []
const showKeys = customConfig.map((key: string) => key.toLowerCase())
hideList.unshift(...fixedList)
showList.unshift(...fixedList)
for (const key of keys) {
if (!key.startsWith('iz') || asideMap[key] === undefined)
continue
onList.value = showList
offList.value = hideList
return { showList, hideList }
}
const name = asideMap[key]?.label
const isDefaultFilter = asideMap[key]?.isDefaultFilter
function generateDefaultList() {
return Object.keys(workPackageMap).reduce((acc, key) => {
const { label, isDefault } = workPackageMap[key]
//
const isChecked = asideMap[key].isDefaultFilter || showKeys.includes(key)
offList.push({
id: key,
name: name || '未配置',
fix: isDefaultFilter,
checked: isChecked,
})
isChecked && selectIds.value.push(key)
}
onList = showKeys.reduce((acc, key) => {
const isDefaultFilter = asideMap[key]?.isDefaultFilter
if (isDefault) {
// ()
if (isDefaultFilter === false) {
const config = {
id: key,
name: label || '未配置',
fix: true,
checked: true,
name: asideMap[key].label || '未配置',
fix: asideMap[key].isDefaultFilter,
}
return [...acc, config]
}
@ -75,31 +98,34 @@ function generateDefaultList() {
return acc
}
}, [])
const fixedList = generateDefaultList()
onList.unshift(...fixedList)
return { showList: onList, hideList: offList }
}
const show = ref(false)
const checkAll = ref(false)
finalStore.$subscribe(() => {
const customConfig = finalStore.getCustomConfig
function showModal() {
show.value = true
}
if (customConfig === null)
return
function closeModal() {
show.value = false
}
const { showList, hideList } = generatList(customConfig)
onList.value = showList
offList.value = hideList
})
async function handleSumbit(e: MouseEvent) {
e.preventDefault()
closeModal()
}
defineExpose({
showModal,
})
generatList()
const param = onList.value.filter(item => !asideMap[item.id].isDefaultFilter).map((item) => {
return item.id
}).join(',')
const selectIds = ref<string[]>([])
await setFilter({ searchcount: param, type: 1 })
finalStore.fetchCustomConfig()
closeModal()
}
function onCheckAllChange(value) {
const ids: string[] = []
@ -202,37 +228,49 @@ function removeHandler(id: string) {
if (index !== -1)
onList.value.splice(index, 1)
}
const offKeyword = ref('')
const onKeyword = ref('')
const leftInputHandler = debounce((keyword) => {
offKeyword.value = keyword
}, 300)
const rightInputHandler = debounce((keyword) => {
onKeyword.value = keyword
}, 300)
</script>
<template>
<n-modal v-model:show="show" transform-origin="center">
<n-modal v-model:show="show" transform-origin="center" :mask-closable="false">
<n-card class="cardstyle" :bordered="false" size="huge" role="dialog" aria-modal="true">
<div class="wrapper">
<span class="wrapper-title">自定义任务包字段</span>
<span class="wrapper-title">自定义筛选</span>
<div class="wrapper-bar">
<div class="wrapper-info">
<span :style="{ 'margin-left': '18px' }">字段信息</span>
<span :style="{ 'margin-left': '18px' }">筛选项信息</span>
</div>
</div>
<n-grid cols="4" class="mt-4 proCard" responsive="screen" :x-gap="24">
<n-grid-item span="3">
<n-grid cols="24" class="mt-4 proCard" responsive="screen" :x-gap="24">
<n-grid-item span="11">
<NCard
:title="allCount" class="dragcardStyle" :segmented="{ content: true, footer: true }" size="small"
:bordered="false"
>
<div>
<n-input placeholder="搜索关键字">
<n-input placeholder="搜索关键字" @input="leftInputHandler">
<template #suffix>
<SvgIcon size="14px" name="magnifying-1" />
</template>
</n-input>
<div class="draggable-ul">
<div class="draggable-li">
<n-checkbox v-model:checked="checkAll" label="全部" @update:checked="onCheckAllChange" />
</div>
<div class="content">
<n-scrollbar style="max-height: 500px;border: 1px solid #cad2dd;border-radius: 2px;">
<div class="draggable-ul">
<div class="draggable-li">
<n-checkbox v-model:checked="checkAll" label="全部" @update:checked="onCheckAllChange" />
</div>
<div
v-for="item in offList" :key="item.id" style="width: 170px;"
v-for="item in offList" v-show="item.name.includes(offKeyword)" :key="item.id"
:class="{ 'disable-check': item.fix }" class="draggable-li"
>
<n-checkbox
@ -241,11 +279,14 @@ function removeHandler(id: string) {
/>
</div>
</div>
</div>
</n-scrollbar>
</div>
</NCard>
</n-grid-item>
<n-grid-item>
<n-grid-item style="display: flex;align-items: center;" span="2">
<SvgIcon size="20" name="switchsvg" />
</n-grid-item>
<n-grid-item span="11">
<NCard
:title="selectCount" class="dragcardStyle" :segmented="{ content: true, footer: true }" size="small"
:bordered="false"
@ -254,23 +295,26 @@ function removeHandler(id: string) {
<span class="textbtnStyle" @click="clearDragSource"></span>
</template>
<div>
<n-input placeholder="搜索关键字">
<n-input placeholder="搜索关键字" @input="rightInputHandler">
<template #suffix>
<SvgIcon size="14px" name="magnifying-1" />
</template>
</n-input>
<VueDraggable v-model="onList" class="draggable-ul" :animation="150" group="shared">
<div
v-for="item in onList" :key="item.id" :class="{ fix: item.fix }"
class="cursor-move draggable-item"
>
<span class="ml-2">{{ item.name }}</span>
<SvgIcon
v-if="!item.fix" size="16px" style="display: block; margin-left: auto; cursor: pointer"
name="clear" @click="removeHandler(item.id)"
/>
</div>
</VueDraggable>
<n-scrollbar style="max-height: 500px;border: 1px solid #cad2dd;border-radius: 2px;" class="scroll">
<VueDraggable v-model="onList" class="draggable-ul" filter=".draggable-li[draggable='false']" :animation="150" group="shared">
<div
v-for="item in onList" v-show="item.name.includes(onKeyword)" :key="item.id" :draggable="!item.fix"
:class="{ fix: item.fix }" class="cursor-move draggable-li"
>
<SvgIcon v-show="!item.fix" name="drag" size="24" />
<span class="ml-2">{{ item.name }}</span>
<SvgIcon
v-if="!item.fix" size="16px" style="display:block;margin-left: auto;cursor: pointer;"
name="clear" @click="removeHandler(item.id)"
/>
</div>
</VueDraggable>
</n-scrollbar>
</div>
</NCard>
</n-grid-item>
@ -316,8 +360,8 @@ function removeHandler(id: string) {
position: relative;
&:before {
background-color: #1980ff;
content: '';
background-color: #1980FF;
content: "";
width: 5px;
border-radius: 2px;
top: 0;
@ -333,37 +377,26 @@ function removeHandler(id: string) {
}
.cardstyle {
width: 820px;
width: 620px;
height: 800px;
--n-padding-bottom: 20px;
--n-padding-left: 24px;
}
.textbtnStyle {
cursor: pointer;
color: #1980ff;
color: #1980FF;
}
.draggable-ul {
width: 100%;
overflow: hidden;
border: 1px solid #cad2dd;
border-top: 0px;
border-radius: 2px;
display: block;
.content {
display: flex;
flex-wrap: wrap;
}
.draggable-li {
width: 100%;
padding: 10px 16px;
color: #333;
}
.draggable-item {
padding: 10px 16px;
color: #333;
border-bottom: 1px solid #efeff5;
display: flex;
align-items: center;
}
@ -379,6 +412,6 @@ function removeHandler(id: string) {
::v-deep(.n-card > .n-card-header) {
--n-padding-top: 0px;
--n-padding-bottom: 12px;
--n-padding-bottom: 12px
}
</style>

@ -4,5 +4,6 @@ import RepeatModal from './RepeatModal.vue'
import RepeatTaskTableModal from './RepeatTaskTableModal.vue'
import Action from './Action.vue'
import RejectModal from './RejectModal.vue'
import CustomFilterModalVue from './CustomFilterModalVue.vue'
export { CustomTabelModal, ImportExcelModal, RepeatModal, RepeatTaskTableModal, Action, RejectModal }
export { CustomTabelModal, ImportExcelModal, RepeatModal, RepeatTaskTableModal, Action, RejectModal, CustomFilterModalVue }

@ -454,7 +454,7 @@ function reload() {
<style lang="less" scoped>
.wrapper {
display: flex;
flex: auto;
flex: 1;
overflow: hidden;
flex-direction: column;
box-sizing: border-box;

@ -85,11 +85,13 @@ configStore.$subscribe(() => {
if (config === null || customConfig === null)
return
const showKeys = customConfig.searchcount.split(',')
const showKeys = [...customConfig].filter(key => !asideMap[key].isDefaultFilter)
const defaultKeys = Object.keys(asideMap).filter(key => asideMap[key].isDefaultFilter)
showKeys.unshift(...defaultKeys)
Object.keys(config).forEach((key) => {
if (key.startsWith('iz'))
asideVisible[key] = showKeys.includes(key) && config[key] === 'Y'
if (key.startsWith('iz') && asideMap[key] !== undefined)
asideVisible[key] = (showKeys.includes(key) || asideMap[key].isDefaultFilter) && config[key] === 'Y'
})
const items = showKeys.reduce((acc, key) => {

@ -23,8 +23,7 @@ const inputHandler = debounce((keyword) => {
configStore.$subscribe(() => {
const customConfig = configStore.getCustomConfig
const searchcount = customConfig?.searchcount || ''
const keys = searchcount ? searchcount.split(',') : []
const keys = customConfig ? [...customConfig] : []
if (keys.length === 0)
return

@ -64,7 +64,7 @@ function generatList(config, customConfig) {
const keys = Object.keys(config)
let onList: object[] = []
const offList: object[] = []
const showKeys = customConfig.searchcount.split(',').map((key: string) => key.toLowerCase())
const showKeys = [...customConfig]
for (const key of keys) {
if (!key.startsWith('iz') || config[key] === 'N' || asideMap[key] === undefined)
@ -89,8 +89,10 @@ function generatList(config, customConfig) {
}
onList = showKeys.reduce((acc, key) => {
//
if (config[key] === 'Y') {
const isDefaultFilter = asideMap[key]?.isDefaultFilter
// && ()
if (config[key] === 'Y' && isDefaultFilter === false) {
const config = {
id: key,
name: asideMap[key].label || '未配置',
@ -105,6 +107,7 @@ function generatList(config, customConfig) {
const fixedList = generateDefaultList(config)
offList.unshift(...fixedList)
onList.unshift(...fixedList)
return { showList: onList, hideList: offList }
}
@ -123,11 +126,11 @@ configStore.$subscribe(() => {
async function handleSumbit(e: MouseEvent) {
e.preventDefault()
const param = onList.value.map((item) => {
const param = onList.value.filter(item => !asideMap[item.id].isDefaultFilter).map((item) => {
return item.id
}).join(',')
await setFilter({ searchcount: param })
await setFilter({ searchcount: param, type: 0 })
configStore.fetchCustomConfig()
closeModal()
}
@ -321,12 +324,12 @@ onMounted(()=>{
</template>
</n-input>
<n-scrollbar style="max-height: 500px;border: 1px solid #cad2dd;border-radius: 2px;" class="scroll">
<VueDraggable v-model="onList" class="draggable-ul" :animation="150" group="shared">
<VueDraggable v-model="onList" filter=".draggable-li[draggable='false']" class="draggable-ul" :animation="150" group="shared">
<div
v-for="item in onList" v-show="item.name.includes(onKeyword)" :key="item.id" :class="{ fix: item.fix }"
v-for="item in onList" v-show="item.name.includes(onKeyword)" :key="item.id" :draggable="!item.fix" :class="{ fix: item.fix }"
class="cursor-move draggable-li"
>
<SvgIcon name="drag" size="24" />
<SvgIcon v-show="!item.fix" name="drag" size="24" />
<span class="ml-2">{{ item.name }}</span>
<SvgIcon
v-if="!item.fix" size="16px" style="display:block;margin-left: auto;cursor: pointer;"

@ -14,6 +14,7 @@ import img2 from '@/assets/images/2.jpg'
import img3 from '@/assets/images/3.jpg'
import img4 from '@/assets/images/4.jpg'
import img5 from '@/assets/images/5.jpg'
import avatar from '@/assets/images/avatar.jpg'
import { timeOptions, viewOptions } from '@/config/home'
import { useWindowSizeFn } from '@/hooks/event/useWindowSizeFn'
import { useConfig } from '@/store/modules/asideConfig'
@ -78,6 +79,8 @@ const layout = debounce(() => {
_imagesload.on('done', (instance) => {
(_masonry as any).layout()
if (!el.value)
return
const scrollHeight = el.value!.scrollHeight
const clientHeight = el.value!.clientHeight
const top = scrollHeight - clientHeight - 20
@ -251,10 +254,11 @@ watch(() => configStore.asideValue, (newVal, oldVal) => {
}, { deep: true })
async function refreshHandler() {
pagination.pageNo = 1
pagination.pageNo = 0
pagination.pageSize = 30
listData.value.length = 0
loading.value = true
canloadMore = true
const contentParams = {
search_month: timeRange.value,
@ -277,6 +281,10 @@ async function refreshHandler() {
listData.value = list
}
function getAvatar(url: string): string {
return url ? getImgUrl(url) : avatar
}
</script>
<template>
@ -316,7 +324,7 @@ async function refreshHandler() {
<n-image class="wrapper-content-item-img" :img-props="{ onClick: hideDownload }" :class="{ 'wrapper-content-item-img-fit': viewMode !== 'masonry' }" :src="item.imgUrl" />
<div class="wrapper-content-item-info">
<div class="wrapper-content-item-info-left">
<n-avatar :src="getImgUrl(item.uphead)" class="wrapper-content-item-info-avatar" round />
<n-avatar :src="getAvatar(item.uphead)" class="wrapper-content-item-info-avatar" round />
<span>{{ item.upname }}</span>
</div>
<div class="wrapper-content-item-info-right">

@ -1,17 +1,7 @@
<script lang="ts" setup>
import { computed, reactive, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { reactive, ref } from 'vue'
import { useMessage } from 'naive-ui'
// import captcha from './captcha.vue'
import { PageEnum } from '@/enums/pageEnum'
import { useUserStore } from '@/store/modules/user'
import { ResultEnum } from '@/enums/httpEnum'
import { getFilter, setFilter } from '@/api/home/filter'
import { getConfig } from '@/api/system/user'
import { forgetPassword, getCode } from '@/api/login/login'
import { asideMap } from '@/config/aside'
import { forgetPassword, getCode, updateSUser } from '@/api/login/login'
const emit = defineEmits(['close', 'forget'])
interface FormState {
@ -28,36 +18,46 @@ interface FormForget {
phonecode: string
}
interface FormSure {
newPassword: string
rePasswrod: string
loginname: string
}
const formRef = ref()
const formRefSure = ref()
const message = useMessage()
const loading = ref(false)
const autoLogin = ref(true)
const LOGIN_NAME = PageEnum.BASE_LOGIN_NAME
const userStore = useUserStore()
const router = useRouter()
const route = useRoute()
const show = ref(false)
const flag = ref(false)
const flag = ref(true)
const formForget: FormForget = reactive({
agentcode: '三方系统标识8',
loginname: '13311111111',
phone: '13311111111',
phonecode: '',
})
const formInline: FormState = reactive({
enterprisecode: '三方系统标识8',
username: '13311111111',
password: '123456',
captcha: '',
})
const formSure: FormSure = reactive({
newPassword: '',
rePasswrod: '',
loginname: '13311111111',
})
const tab = ref(0)
const countTime = ref('获取验证码')
const rules = {
enterprisecode: { required: true, message: '请输入企业编码', trigger: 'blur' },
loginname: { required: true, message: '请输入用户名', trigger: 'blur' },
password: { required: true, message: '请输入密码', trigger: 'blur' },
captcha: { required: true, message: '请输入验证码', trigger: 'blur' },
reenteredPassword: [
phonecode: { required: true, message: '请输入验证码', trigger: 'blur' },
newPassword: { required: true, message: '请输入新密码', trigger: 'blur' },
rePasswrod: [
{
required: true,
message: '请再次输入密码',
@ -72,7 +72,7 @@ const rules = {
}
function validatePasswordSame(rule: any, value: string): boolean {
return value === formInline.password
return value === formSure.newPassword
}
function handleSubmit(e) {
@ -80,7 +80,6 @@ function handleSubmit(e) {
formRef.value.validate(async (errors) => {
if (!errors) {
const { loginname, phone, phonecode, agentcode } = formForget
message.loading('登录中...')
loading.value = true
const params = {
@ -92,41 +91,48 @@ function handleSubmit(e) {
try {
const res = await forgetPassword(params)
console.log(res)
const { code, message: msg } = await userStore.login(params)
await userStore.getInformation()
const response = await getFilter()
//
if (response.data === null) {
const systemConfig = await getConfig()
const onList: string[] = []
Object.keys(systemConfig.data).forEach((key) => {
//
if (key.startsWith('iz') && systemConfig.data[key] === 'Y' && asideMap[key]?.isDefaultFilter)
onList.push(key)
})
await setFilter({ searchcount: onList.join(',') })
if (res.code === 'OK') {
formSure.loginname = res.data.loginname
tab.value = 1
}
}
finally {
loading.value = false
}
}
else {
message.error('请填写完整信息')
}
})
}
message.destroyAll()
if (code === ResultEnum.SUCCESS) {
const toPath = decodeURIComponent((route.query?.redirect || '/') as string)
message.success('登录成功,即将进入系统')
if (route.name === LOGIN_NAME)
router.replace('/')
else router.replace(toPath)
}
else {
message.info(msg || '登录失败')
}
function handleSure(e) {
e.preventDefault()
formRefSure.value.validate(async (errors) => {
if (!errors) {
const { newPassword, rePasswrod, loginname } = formSure
loading.value = true
const params = {
newPassword,
rePasswrod,
loginname,
}
try {
const res = await updateSUser(params)
if (res.code === 'OK')
message.success('修改成功')
else
message.error(res.message)
}
finally {
loading.value = false
}
}
else {
message.error('请填写完整信息,并且进行验证码校验')
message.error('请填写完整信息')
}
})
}
@ -143,12 +149,17 @@ function computedForm() {
return !formInline.enterprisecode || !formInline.username || !formInline.password
}
function computedFormSure() {
return !formSure.newPassword || !formSure.rePasswrod
}
async function sendCode(value) {
if (!flag.value)
return
flag.value = false
const res = await getCode({
phone: 13311111111,
agentcode: '三方系统标识8',
})
console.log(res)
startCount()
}
@ -160,7 +171,7 @@ function startCount() {
if (time === 0) {
clearInterval(timer)
countTime.value = '获取验证码'
flag.value = false
flag.value = true
}
}, 1000)
}
@ -224,23 +235,23 @@ function forget() {
</n-form>
</div>
<div v-if="tab === 1" class="form-1">
<n-form ref="formRef" label-placement="left" size="large" :model="formInline" :rules="rules">
<n-form-item class="form-item" path="password">
<n-input v-model:value="formInline.password" class="item-input" type="password" show-password-on="click" placeholder="请输入8-16位密码必须包含英文及数字">
<n-form ref="formRefSure" label-placement="left" size="large" :model="formSure" :rules="rules">
<n-form-item class="form-item" path="newPassword">
<n-input v-model:value="formSure.newPassword" class="item-input" type="password" show-password-on="click" placeholder="请输入8-16位密码必须包含英文及数字">
<template #prefix>
<svg-icon size="20" name="password" />
</template>
</n-input>
</n-form-item>
<n-form-item class="form-item" path="password">
<n-input v-model:value="formInline.password" class="item-input" type="password" show-password-on="click" placeholder="请再次确认输入新密码">
<n-form-item class="form-item" path="rePasswrod">
<n-input v-model:value="formSure.rePasswrod" class="item-input" type="password" show-password-on="click" placeholder="请再次确认输入新密码">
<template #prefix>
<svg-icon size="20" name="password" />
</template>
</n-input>
</n-form-item>
<n-form-item class="form-item">
<n-button :class="{ 'btn-disabled': computedForm() }" class="btn" type="primary" size="large" :loading="loading" block @click="handleSubmit">
<n-button :class="{ 'btn-disabled': computedFormSure() }" class="btn" type="primary" size="large" :loading="loading" block @click="handleSure">
确定
</n-button>
</n-form-item>

@ -7,9 +7,6 @@ import { useMessage } from 'naive-ui'
import { PageEnum } from '@/enums/pageEnum'
import { useUserStore } from '@/store/modules/user'
import { ResultEnum } from '@/enums/httpEnum'
import { getFilter, setFilter } from '@/api/home/filter'
import { getConfig } from '@/api/system/user'
import { asideMap } from '@/config/aside'
import { getCode, smsLogin } from '@/api/login/login'
const emit = defineEmits(['close', 'forget'])
@ -35,10 +32,12 @@ const userStore = useUserStore()
const router = useRouter()
const route = useRoute()
const show = ref(false)
const flag = ref(true)
const formInline: FormState = reactive({
enterprisecode: '三方系统标识8',
username: '13311111111',
password: '123456',
password: '12345678l',
})
const formSms: FormSms = reactive({
@ -75,23 +74,10 @@ function handleSubmit(e) {
try {
const { code, message: msg } = await userStore.login(params)
await userStore.getInformation()
const response = await getFilter()
//
if (response.data === null) {
const systemConfig = await getConfig()
const onList: string[] = []
Object.keys(systemConfig.data).forEach((key) => {
//
if (key.startsWith('iz') && systemConfig.data[key] === 'Y' && asideMap[key]?.isDefaultFilter)
onList.push(key)
})
await setFilter({ searchcount: onList.join(',') })
}
message.destroyAll()
if (code === ResultEnum.SUCCESS) {
await userStore.getInformation()
message.destroyAll()
const toPath = decodeURIComponent((route.query?.redirect || '/') as string)
message.success('登录成功,即将进入系统')
if (route.name === LOGIN_NAME)
@ -99,6 +85,7 @@ function handleSubmit(e) {
else router.replace(toPath)
}
else {
message.destroyAll()
message.info(msg || '登录失败')
}
}
@ -126,25 +113,12 @@ function handleSmsSubmit(e) {
agentcode,
phonecode,
})
console.log(res)
const { code, message: msg } = res
if (code === ResultEnum.SUCCESS) {
// const { code, message: msg } = await userStore.login(params)
await userStore.getInformation()
const response = await getFilter()
//
if (response.data === null) {
const systemConfig = await getConfig()
const onList: string[] = []
Object.keys(systemConfig.data).forEach((key) => {
//
if (key.startsWith('iz') && systemConfig.data[key] === 'Y' && asideMap[key]?.isDefaultFilter)
onList.push(key)
})
await setFilter({ searchcount: onList.join(',') })
}
await userStore.getInformation()
message.destroyAll()
if (code === ResultEnum.SUCCESS) {
message.destroyAll()
const toPath = decodeURIComponent((route.query?.redirect || '/') as string)
message.success('登录成功,即将进入系统')
if (route.name === LOGIN_NAME)
@ -152,6 +126,7 @@ function handleSmsSubmit(e) {
else router.replace(toPath)
}
else {
message.destroyAll()
message.info(msg || '登录失败')
}
}
@ -178,11 +153,14 @@ function computedForm() {
}
async function sendCode(value) {
if (!flag.value)
return
flag.value = false
const res = await getCode({
phone: 13311111111,
agentcode: '三方系统标识8',
})
console.log(res)
startCount()
}
@ -194,7 +172,7 @@ function startCount() {
if (time === 0) {
clearInterval(timer)
countTime.value = '重新获取'
// this.flag = false;
flag.value = true
}
}, 1000)
}

@ -1,43 +1,11 @@
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useMessage } from 'naive-ui'
import captcha from './captcha.vue'
import { ref } from 'vue'
import Login from './components/Login.vue'
import Forget from './components/Forget.vue'
import { PageEnum } from '@/enums/pageEnum'
import { useUserStore } from '@/store/modules/user'
import { ResultEnum } from '@/enums/httpEnum'
import { getFilter, setFilter } from '@/api/home/filter'
import { getConfig } from '@/api/system/user'
import { asideMap } from '@/config/aside'
interface FormState {
enterprisecode?: string
username: string
password: string
captcha: string
}
const formRef = ref()
const message = useMessage()
const loading = ref(false)
const autoLogin = ref(true)
const LOGIN_NAME = PageEnum.BASE_LOGIN_NAME
const userStore = useUserStore()
const router = useRouter()
const route = useRoute()
const show = ref(true)
const showForget = ref(true)
const show = ref(false)
const ifLogin = ref(true)
const formInline: FormState = reactive({
enterprisecode: '三方系统标识8',
username: '13311111111',
password: '123456',
captcha: '',
})
function showLogin() {
show.value = true
}

@ -6,9 +6,6 @@ import captcha from './captcha.vue'
import { PageEnum } from '@/enums/pageEnum'
import { useUserStore } from '@/store/modules/user'
import { ResultEnum } from '@/enums/httpEnum'
import { getFilter, setFilter } from '@/api/home/filter'
import { getConfig } from '@/api/system/user'
import { asideMap } from '@/config/aside'
interface FormState {
enterprisecode?: string
@ -59,20 +56,6 @@ function handleSubmit(e) {
try {
const { code, message: msg } = await userStore.login(params)
await userStore.getInformation()
const response = await getFilter()
//
if (response.data === null) {
const systemConfig = await getConfig()
const onList: string[] = []
Object.keys(systemConfig.data).forEach((key) => {
//
if (key.startsWith('iz') && systemConfig.data[key] === 'Y' && asideMap[key]?.isDefaultFilter)
onList.push(key)
})
await setFilter({ searchcount: onList.join(',') })
}
message.destroyAll()
if (code === ResultEnum.SUCCESS) {
const toPath = decodeURIComponent((route.query?.redirect || '/') as string)

@ -1,163 +0,0 @@
<script lang="ts" setup>
import { computed, defineOptions, nextTick, onBeforeMount, onMounted, reactive, ref, unref } from 'vue'
import CustomFieldModalVue from '../modal/CustomFieldModal.vue'
import WorkSheetList from './WorkSheetList.vue'
import { useWindowSizeFn } from '@/hooks/event/useWindowSizeFn'
import { getViewportOffset } from '@/utils/domUtils'
import type { PackageListItem } from '/#/workorder'
import { useWorkOrder } from '@/store/modules/workOrder'
defineOptions({ name: 'AsideContent' })
const collapse = ref(false)
const workStore = useWorkOrder()
const filterModalRef = ref(null)
function collapseHandler() {
collapse.value = !collapse.value
}
const asideWidth = computed(() => {
return collapse.value ? 0 : 308
})
const asideStyle = computed(() => {
return {
width: `${asideWidth.value}px`,
}
})
const collapseIcon = computed(() => {
return collapse.value ? 'expand-cir' : 'collapse-cir'
})
const listHeight = ref(700)
function computeListHeight() {
const listEl = document.querySelector('.work-sheet-list')!
const { bottomIncludeBody } = getViewportOffset(listEl)
const height = bottomIncludeBody
listHeight.value = height - 25
}
const listStyle = computed(() => {
return {
height: `${listHeight.value}px`,
}
})
useWindowSizeFn(computeListHeight, 280)
onMounted(() => {
nextTick(() => {
computeListHeight()
})
})
const data = ref<PackageListItem[]>([])
const pagination = reactive({
pageNo: 1,
pageSize: 10,
})
onBeforeMount(async () => {
const orderList = await workStore.fetchOrderList(pagination)
data.value = orderList
})
const asideEnter = ref(false)
const showCollapse = computed(() => {
return collapse.value ? true : asideEnter.value
})
function showFilter() {
const modal = unref(filterModalRef)! as any
modal.showModal()
}
</script>
<template>
<div class="aside" :style="asideStyle" @mouseenter="asideEnter = true" @mouseleave="asideEnter = false">
111fsfsf发送到发
<div v-show="showCollapse" class="aside-collapse">
<div class="aside-collapse-btn" @click="collapseHandler">
<SvgIcon :name="collapseIcon" size="40" />
</div>
</div>
<div class="aside-header">
<div class="aside-header-left">
<svg-icon name="all-worksheet" size="32" />
<span style="margin-left: 8px;">所有工单</span>
</div>
<div class="aside-header-right">
<SvgIcon style="cursor: pointer;margin-left: 10px;" size="18" name="magnifying-1" />
<SvgIcon style="cursor: pointer;margin-left: 10px;" size="18" name="filter" @click="showFilter" />
</div>
</div>
<WorkSheetList :style="listStyle" class="work-sheet-list" :data="data" :active-id="workStore.getActiveId" />
<CustomFieldModalVue ref="filterModalRef" />
</div>
</template>
<style lang="less" scoped>
.aside {
display: flex;
position: relative;
flex-direction: column;
background: #FFF;
border: 1px solid rgb(239, 239, 245);
border-radius: 3px;
box-sizing: border-box;
&-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
width: 100%;
overflow: hidden;
&-left {
display: flex;
align-items: center;
overflow: hidden;
}
&-right {
display: flex;
align-items: center;
overflow: hidden;
}
}
&-divider {
margin-left: 16px;
width: 292px;
height: 1px;
background-color: #e8e8e8;
}
&-collapse {
width: 2px;
height: 100%;
background: #507afd;
position: absolute;
right: 0;
top: 0;
}
&-collapse-btn {
position: absolute;
cursor: pointer;
width: 40px;
height: 40px;
top: calc(15%);
right: -20px;
z-index: 10;
}
}
</style>
../types

@ -1,90 +0,0 @@
<script lang="ts" setup>
import { computed } from 'vue'
import type { PackageListItem } from '/#/workorder'
defineOptions({ name: 'ListItem' })
const props = defineProps({
selected: {
type: Boolean,
default: false,
},
listItem: {
type: Object as PropType<PackageListItem>,
required: true,
},
})
const svgName = computed(() => {
return props.selected ? 'taskpack-select' : 'taskpack'
})
</script>
<template>
<div class="list-item" :class="{ 'list-item-selected': selected }">
<div class="list-item-header">
<div style="display: flex;">
<SvgIcon :name="svgName" size="28" />
<span class="list-item-header-name" :class="{ 'list-item-header-selected': selected }">
{{ listItem.packagename }}
</span>
<span class="list-item-header-selected">({{ listItem.pictureno }})</span>
</div>
<SvgIcon v-show="selected" size="14" name="more-ver" />
</div>
<ul class="list-item-detail">
<li>筛选时间{{ listItem.createTime }}</li>
<li>执行人{{ listItem.createBy }}</li>
</ul>
<div class="list-item-divider" />
</div>
</template>
<style lang="less" scoped>
.list-item {
padding: 12px 0px 12px 16px;
position: relative;
&-header {
display: flex;
align-items: center;
&-name {
font-size: 16px;
font-weight: bold;
color: #333333;
line-height: 22px;
margin: 0px 0px 8px 8px;
}
&-selected {
color: #507AFD;
}
}
&-selected {
background-color: #f2f5fe;
}
&-detail {
margin-left: 36px;
li {
font-size: 13px;
color: #666666;
line-height: 18px;
margin-bottom: 8px;
}
}
&-divider {
width: 100%;
height: 1px;
background-color: #e8e8e8;
position: absolute;
bottom: 0px;
}
}
</style>
../types

@ -1,37 +0,0 @@
<script lang="ts" setup>
import type { PackageListItem } from '/#/workorder'
import ListItem from './ListItem.vue'
import { useWorkOrder } from '@/store/modules/workOrder'
defineOptions({ name: 'WorkSheetList' })
defineProps({
activeId: {
type: String,
required: true,
},
data: {
type: Object as PropType<PackageListItem[]>,
required: true,
},
})
const workStore = useWorkOrder()
function selectHandler(id: string, index: number) {
workStore.setActive(index)
}
</script>
<template>
<n-scrollbar>
<ListItem
v-for="(item, index) in data" :key="item.id" :selected="activeId === item.id" :list-item="item"
@click="selectHandler(item.id, index)"
/>
</n-scrollbar>
</template>
<style lang="less" scoped>
</style>
../types

@ -1,33 +1,48 @@
<script lang="ts" setup>
import { onUnmounted, reactive, ref } from 'vue'
import { reactive, ref, toRefs } from 'vue'
import { useMessage } from 'naive-ui'
import type { SetTFParam } from '/#/api'
import { useWorkOrder } from '@/store/modules/workOrder'
import { clearTF } from '@/api/work/work'
import { format } from 'date-fns'
import { msgOne, readMsg } from '@/api/message/message'
const props = defineProps({
id: {
type: String,
default: '',
},
})
const message = useMessage()
const state: any = reactive({
detail: {},
})
const { detail } = toRefs(state)
const workStore = useWorkOrder()
const selectTask = ref<any>(null)
async function getDetail() {
const res = await msgOne({ id: props.id })
if (!state.detail.readFlag)
clearMsg()
const taskDetailInfo = ref<any>({})
if (res.code === 'OK')
state.detail = res.data
async function getDetail() {
const res = await clearTF(workStore.activeId, selectTask.value.id)
if (res.code === 'OK') {
taskDetailInfo.value.iztrueorfalse = null
message.info('清除标记成功')
}
else { message.error(res.message) }
else
message.error(res.message)
}
async function clearMsg() {
const res = await readMsg({ msgid: props.id })
}
getDetail()
</script>
<template>
<div class="wrapper-message">
<div class="left-card">
<div class="title">
关于系统升级的通知
{{ detail.titile }}
</div>
<div class="content" v-html="detail.msgContent" />
</div>
<div class="right-card">
<img class="icon-set" src="@/assets/images/message/set.png" alt="">
@ -41,7 +56,7 @@ async function getDetail() {
创建人
</div>
<div class="value">
系统管理员
{{ detail.userNcame }}
</div>
</div>
<div class="form-item flex">
@ -50,7 +65,7 @@ async function getDetail() {
发布时间
</div>
<div class="value time">
2023-10-31 23:12:00
{{ format(detail.sendTime * 1000, 'yyyy-MM-dd HH:mm:ss') }}
</div>
</div>
<div class="form-item flex margin-no">
@ -60,7 +75,7 @@ async function getDetail() {
</div>
<div class="value">
<div class="tag">
系统消息
{{ detail.msgCategory === 1 ? '审批通知' : '系统通知' }}
</div>
</div>
</div>
@ -93,7 +108,13 @@ async function getDetail() {
text-align: center;
color: #333333;
line-height: 40px;
margin-bottom: 32px;
}
.content{
padding: 0 32px;
}
}
.right-card{

@ -1,9 +1,7 @@
<script lang="ts" setup>
import { onUnmounted, reactive, ref, toRefs, watch } from 'vue'
import type { PictureSortParam } from '/#/api'
import { useWorkOrder } from '@/store/modules/workOrder'
import { getPackageTaskList, getTaskDetailInfo, getTaskDetailPictureList } from '@/api/work/work'
import { getMessageList } from '@/api/message/message'
import { reactive, ref, toRefs } from 'vue'
import { format } from 'date-fns'
import { getMessageList, readAllMsg, readMsg } from '@/api/message/message'
import iconApproveActive from '@/assets/images/message/approve-active.png'
import iconApprove from '@/assets/images/message/approve.png'
import iconSystemActive from '@/assets/images/message/system-active.png'
@ -11,10 +9,11 @@ import iconSystem from '@/assets/images/message/system.png'
import iconArrowActive from '@/assets/images/message/arrow-active.png'
import iconArrow from '@/assets/images/message/arrow.png'
import iconClear from '@/assets/images/message/clear.png'
import iconArrowDown from '@/assets/images/message/arrow-down.png'
const emit = defineEmits(['goDetail'])
const totalCount = ref(0)
const hasNextPage = ref(false)
const state = reactive({
tabList: [
@ -22,78 +21,68 @@ const state = reactive({
name: '审批通知',
icon: iconApprove,
activeIcon: iconApproveActive,
value: 0,
value: 1,
},
{
name: '系统消息',
icon: iconSystem,
activeIcon: iconSystemActive,
value: 1,
value: 2,
},
],
list: [] as any,
pageNo: 1,
})
const { list, tabList } = toRefs(state)
const packagepagination = reactive({
pageNo: 1,
pageSize: 10,
})
const taskpagination = reactive({
pageNo: 1,
pageSize: 10,
})
const sortBy: PictureSortParam = {
orderbyname: 'desc',
orderbyvalue: 'fromuptime',
}
const workStore = useWorkOrder()
const selectTask = ref<any>(null)
const taskList = ref<any[]>([])
const taskDetailInfo = ref<any>({})
const taskDetailPictureList = ref<any[]>([])
const tab = ref(0)
const tab = ref(1)
async function getList(value) {
async function getList() {
const res = await getMessageList({
pageNo: '1',
pageNo: state.pageNo,
pageSize: '10',
msgCategory: value,
msgCategory: tab.value,
})
console.log(res)
state.list = res.list
if (res.code === 'OK') {
hasNextPage.value = res.data.hasNextPage
state.list = state.list.concat(res.data.list)
}
}
getList('1')
getList()
watch(() => workStore.activeId, async (newValue, oldValue) => {
const res = await getPackageTaskList(newValue, packagepagination)
const { data } = res
taskList.value = data
async function clearMsg() {
const res = await readAllMsg({ msgCategory: tab.value })
if (res.code === 'OK') {
state.list = []
state.pageNo = 1
getList()
}
}
if (taskList.value.length > 0)
handleSelect(taskList.value[0])
})
function switchTab(type: number) {
tab.value = type
state.list = []
state.pageNo = 1
getList()
}
async function handleSelect(item: any) {
selectTask.value = item
const taskId = item.id
taskDetailInfo.value = await getTaskDetailInfo(taskId, workStore.activeId)
function goDetail(item) {
if (tab.value === 1)
clearMsgOne(item.id)
const { data, total } = await getTaskDetailPictureList(workStore.activeId, taskId, { ...taskpagination, ...sortBy })
taskDetailPictureList.value = data
totalCount.value = total
else
emit('goDetail', item.id)
}
function switchTab(type: number) {
tab.value = type
getList(type)
async function clearMsgOne(id) {
const res = await readMsg({ msgid: id })
}
function goDetail(id) {
emit('goDetail', id)
function getMore() {
state.pageNo += 1
getList()
}
</script>
@ -103,7 +92,7 @@ function goDetail(id) {
<div class="header-title">
消息通知
</div>
<div class="clear">
<div class="clear" @click="clearMsg">
<img class="icon-clear" :src="iconClear" alt="">
清除未读
</div>
@ -128,14 +117,14 @@ function goDetail(id) {
</div>
</div>
<div class="list">
<div v-for="(item, index) in list" :key="item.id" :class="index === 0 ? 'pt0' : ''" class="item" @click="goDetail(item)">
<div v-for="(item, index) in list" :key="item.id" :class="{ 'pt0': index === 0, 'item-disabled': item.readFlag }" class="item" @click="goDetail(item)">
<div class="left left">
<div class="num">
{{ item.pictureno }}
<div class="point" />
{{ format(item.sendTime * 1000, 'dd') }}
<div v-if="!item.readFlag" class="point" />
</div>
<div class="date">
{{ item.createTime }}
{{ format(item.sendTime * 1000, 'yyyy-MM') }}
</div>
</div>
<div class="middle">
@ -152,13 +141,17 @@ function goDetail(id) {
</div> -->
<div class="subtitle">
<span class="name">{{ item.userName }}</span>
<span class="time">{{ item.createTime }}</span>
<span class="time">{{ format(item.sendTime * 1000, 'yyyy-MM-dd HH:mm:ss') }}</span>
</div>
</div>
<div class="look">
查看
</div>
</div>
<div v-if="hasNextPage" class="more" @click="getMore">
查看更多<img class="icon-more" :src="iconArrowDown" alt="">
</div>
</div>
</div>
</div>
@ -173,6 +166,7 @@ function goDetail(id) {
background: #FFF;
border-radius: 3px;
height: calc(100vh - 88px);
position: relative;
.header{
padding: 24px;
@ -264,6 +258,31 @@ function goDetail(id) {
.list{
margin-left: 24px;
flex: 1;
overflow-y: auto;
padding-bottom: 97px;
box-sizing: border-box;
height: calc(100vh - 88px - 76px);
.more{
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-family: PingFang SC, PingFang SC-Regular;
text-align: left;
color: #666666;
position: absolute;
bottom: 40px;
left: 50%;
background: #fff;
cursor: pointer;
.icon-more{
width: 14px;
height: 14px;
margin-left: 6px;
}
}
.item{
display: flex;
@ -272,6 +291,10 @@ function goDetail(id) {
flex: 1;
padding: 16px 0 16px 25px;
border-bottom: 1px solid #eeeeee;
&-disabled{
opacity: 0.5;
}
}
.pt0{

@ -1,8 +1,6 @@
<script lang="ts" setup>
import { onUnmounted, reactive, ref } from 'vue'
import Aside from './aside/Aside.vue'
import Content from './content/Content.vue'
import { ref } from 'vue'
import List from './content/List.vue'
import Detail from './content/Detail.vue'
const type = ref('1')
@ -16,12 +14,8 @@ function goDetail(value) {
<template>
<div class="main">
<!-- 侧边 -->
<!-- <Aside /> -->
<!-- 内容 -->
<Content v-if="type === '1'" @go-detail="goDetail" />
<Detail v-else />
<List v-if="type === '1'" @go-detail="goDetail" />
<Detail v-else :id="id" />
</div>
</template>

@ -1,167 +0,0 @@
<script lang="ts" setup>
import { computed, onBeforeMount, ref } from 'vue'
import { useDictionary } from '@/store/modules/dictonary'
const emit = defineEmits<{
(e: 'commit', id: any, desc: null | string)
}>()
const dictonaryStore = useDictionary()
const show = ref(false)
const cardStyle = {
'width': '520px',
'--n-padding-bottom': '10px',
'--n-padding-left': '0px',
}
function showModal() {
show.value = true
}
function closeModal() {
show.value = false
}
defineExpose({
showModal,
})
const options = ref<any[]>([])
const selectId = ref(null)
const otherValue = ref(null)
const showOther = computed(() => {
for (const item of options.value) {
if (item.value === selectId.value && item.label === '其他')
return true
}
return false
})
async function handleSumbit(e: MouseEvent) {
e.preventDefault()
closeModal()
emit('commit', selectId.value, otherValue.value)
}
onBeforeMount(async () => {
const tfList = await dictonaryStore.fetchTFList()
options.value = tfList
})
</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">
<span class="wrapper-left">选择判假原因</span>
<div class="wrapper-right">
<div class="wrapper-right-close" @pointerdown="closeModal">
<div class="wrapper-right-icon" />
</div>
</div>
</div>
<div class="wrapper-content">
<span>判假原因</span>
<n-select v-model:value="selectId" style="margin-top: 10px;" :options="options" />
<n-input v-show="showOther" v-model:value="otherValue" style="margin-top: 10px;" type="textarea" />
</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: space-between;
align-items: center;
padding: 10px;
}
&-left {
font-weight: bold;
font-size: 16px;
}
&-right {
&-close {
width: 18px;
height: 18px;
cursor: pointer;
}
&-icon {
background: #000;
display: inline-block;
width: 18px;
height: 1px;
transform: rotate(45deg);
-webkit-transform: rotate(45deg);
margin-bottom: 8px;
&:after {
content: '';
display: block;
width: 18px;
height: 1px;
background: #000;
transform: rotate(-90deg);
-webkit-transform: rotate(-90deg);
}
}
}
&-content {
padding: 18px 10px;
}
&-footer {
display: flex;
justify-content: flex-end;
}
&-info {
font-weight: bold;
position: relative;
&:before {
background-color: #1980ff;
content: '';
width: 5px;
border-radius: 2px;
top: 0;
bottom: 0;
position: absolute;
}
}
}
::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>

@ -1,19 +1,14 @@
<script lang="ts" setup>
import { useTaskStore } from '@/store/modules/task'
import { useUser } from '@/store/modules/user'
import emitter from '@/utils/mitt'
import { computed, onBeforeMount, onMounted, onUnmounted, reactive, ref, unref, watch } from 'vue'
import { debounce } from 'lodash-es'
import TaskList from './TaskList.vue'
import type { TaskListItem } from '/#/task'
import { useTaskStore } from '@/store/modules/task'
import { useUser } from '@/store/modules/user'
const CustomFieldModalRef = ref(null)
const collapse = ref(false)
const taskStore = useTaskStore()
const userStore = useUser()
const pagination = reactive({
pageNo: 1,
pageSize: 10,
})
const taskListRef = ref<HTMLDivElement | null>(null)
function collapseHandler() {
collapse.value = !collapse.value
@ -33,49 +28,30 @@ const collapseIcon = computed(() => {
return collapse.value ? 'expand-cir' : 'collapse-cir'
})
const data = ref<TaskListItem[]>([])
onBeforeMount(async () => {
const id = userStore.getUserInfo.id
const orderList = await taskStore.fetchApprovalList(pagination, id)
data.value = orderList
})
const count = computed(() => {
return data.value.length
})
const asideEnter = ref(false)
const showCollapse = computed(() => {
return collapse.value ? true : asideEnter.value
})
onMounted(() => {
emitter.on('refresh', refreshHandler)
})
onUnmounted(() => {
emitter.off('refresh', refreshHandler)
})
async function refreshHandler() {
pagination.pageNo = 1
pagination.pageSize = 10
const id = userStore.getUserInfo.id
const orderList = await taskStore.fetchApprovalList(pagination, id)
data.value = orderList
}
watch(() => taskStore.immersion, () => {
collapse.value = true
})
function showFilterModal() {
function showFilter() {
const modal = unref(CustomFieldModalRef)! as any
modal.showModal()
}
const showSearch = ref(false)
function setShowSearch(value: boolean) {
showSearch.value = value
}
const inputHandler = debounce((word) => {
(taskListRef.value as any).search(word)
}, 500)
</script>
<template>
@ -86,16 +62,29 @@ function showFilterModal() {
</div>
</div>
<div class="aside-header">
<div class="aside-header-left">
<svg-icon name="all-worksheet" size="32" />
<span class="aside-header-title">所有请求({{ count }})</span>
<div v-show="!showSearch" class="warpper">
<div class="left">
<svg-icon name="all-worksheet" size="32" />
<span style="margin-left: 8px;">所有请求</span>
</div>
<div class="right">
<SvgIcon
style="cursor: pointer;margin-left: 10px;" size="18" name="magnifying-1"
@click="setShowSearch(true)"
/>
<SvgIcon style="cursor: pointer;margin-left: 10px;" size="18" name="filter" @click="showFilter" />
</div>
</div>
<div class="aside-header-right">
<SvgIcon size="18" name="magnifying-1" />
<SvgIcon style="margin-left: 10px;cursor: pointer;" size="18" name="filter" @click="showFilterModal" />
<div v-show="showSearch" class="warpper">
<n-input style="flex: 1;height: 32px;" placeholder="请输入你需要搜索的内容" @input="inputHandler">
<template #suffix>
<SvgIcon size="14px" name="magnifying-1" />
</template>
</n-input>
<SvgIcon size="16px" style="margin-left: 6px;cursor: pointer;" name="clear" @click="setShowSearch(false)" />
</div>
</div>
<TaskList style="height: calc(100vh - 146px);" class="work-sheet-list" :data="data" :active-id="taskStore.getActiveId!" />
<TaskList ref="taskListRef" style="height: calc(100vh - 146px);" class="work-sheet-list" />
<CustomFieldModal ref="CustomFieldModalRef" />
</div>
</template>
@ -111,13 +100,16 @@ function showFilterModal() {
box-sizing: border-box;
&-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
width: 100%;
overflow: hidden;
.warpper {
display: flex;
justify-content: space-between;
align-items: center;
}
&-title {
margin-left: 8px;
color: #333333;
@ -125,13 +117,13 @@ function showFilterModal() {
font-weight: bold;
}
&-left {
.left {
display: flex;
align-items: center;
overflow: hidden;
}
&-right {
.right {
display: flex;
align-items: center;
overflow: hidden;
@ -150,7 +142,7 @@ function showFilterModal() {
height: 100%;
background: #507afd;
position: absolute;
right: 0;
right: -2px;
top: 0;
}

@ -1,33 +1,115 @@
<script lang="ts" setup>
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue'
import { useInfiniteScroll } from '@vueuse/core'
import ListItem from './ListItem.vue'
import { useTaskStore } from '@/store/modules/task'
import { useUser } from '@/store/modules/user'
import emitter from '@/utils/mitt'
defineOptions({ name: 'WorkSheetList' })
defineProps({
activeId: {
type: String,
required: true,
},
data: {
type: Object as PropType<any[]>,
required: true,
},
})
const taskStore = useTaskStore()
const data = ref<any[]>([])
const activeId = ref('')
const el = ref<HTMLDivElement | null>(null)
const keyword = ref('')
const canloadMore = ref(true)
const userStore = useUser()
const pagination = reactive({
pageNo: 0,
pageSize: 10,
})
function selectHandler(id: string, index: number) {
taskStore.setActive(index)
}
const { isLoading } = useInfiniteScroll(
el as any,
() => {
loadMore()
},
{ distance: 10, interval: 300, canLoadMore: () => {
// console.log('canloadmore excuted!')
return canloadMore.value
} },
)
async function loadMore() {
if (isLoading.value || el.value == null)
return
const more = await fetchList()
data.value.push(...more)
}
async function fetchList() {
try {
pagination.pageNo += 1
const id = userStore.getUserInfo.id
const result = await taskStore.fetchApprovalList(pagination, id)
const { data, pageCount } = result
canloadMore.value = pageCount >= pagination.pageNo && pageCount !== 0
return data || []
}
catch (error) {
canloadMore.value = false
return []
}
}
watch(() => taskStore.activeId, (newVal) => {
activeId.value = newVal
})
function reset() {
pagination.pageNo = 0
pagination.pageSize = 10
canloadMore.value = true
data.value.length = 0
}
async function search(word: string) {
keyword.value = word
reset()
useInfiniteScroll(
el as any,
() => {
loadMore()
},
{ distance: 10, canLoadMore: () => canloadMore.value },
)
}
onMounted(() => {
emitter.on('refresh', refreshHandler)
})
onUnmounted(() => {
emitter.off('refresh', refreshHandler)
})
async function refreshHandler() {
reset()
search('')
}
defineExpose({
search,
})
</script>
<template>
<n-scrollbar class="wrapper">
<ListItem
v-for="(item, index) in data" :key="item.id" :selected="activeId === item.formid" :list-item="item"
@click="selectHandler(item.id, index)"
/>
<n-scrollbar>
<n-spin :show="isLoading">
<div ref="el">
<ListItem
v-for="(item, index) in data" :key="item.id" :selected="activeId === item.formid" :list-item="item"
@click="selectHandler(item.id, index)"
/>
</div>
</n-spin>
</n-scrollbar>
</template>

@ -74,6 +74,9 @@ const showSearch = ref(false)
function setShowSearch(value: boolean) {
showSearch.value = value
if (value === false)
(packageListRef.value as any).search('')
}
const inputHandler = debounce((word) => {

@ -36,7 +36,7 @@ async function loadMore() {
if (isLoading.value || el.value == null)
return
console.log('loadmore')
// console.log('loadmore')
const more = await fetchList()
data.value.push(...more)
}

7
types/api.d.ts vendored

@ -33,6 +33,7 @@ export interface FilterUpdate extends FilterCondition {
}
export interface FilterParam {
type: number
searchcount: string
}
@ -128,3 +129,9 @@ export interface ResetParam {
fromid: string
taskid: string
}
export interface BusinessParam {
pageNo: string
pageSize: string
field: string
}

Loading…
Cancel
Save