上传照片
parent
9f33b86a18
commit
15981273b0
|
|
@ -3,33 +3,72 @@ import fs from 'fs'
|
|||
import path from 'path'
|
||||
|
||||
interface FileWatcherOptions {
|
||||
// 目标可以是文件路径或文件夹路径
|
||||
file: string;
|
||||
fn: (content: string) => void;
|
||||
// 回调函数,接收变化的文件路径、内容(如果有)和变化类型
|
||||
fn: (filePath: string, content?: string, eventType?: 'add' | 'change' | 'unlink') => void;
|
||||
// 防抖延迟,默认300ms
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
export function fileWatcher(options: FileWatcherOptions): Plugin {
|
||||
const {file, fn, delay = 300} = options
|
||||
const targetPath = path.resolve(file)
|
||||
let debounceTimer: NodeJS.Timeout | null = null
|
||||
|
||||
// 检查目标是否为文件夹
|
||||
const isDir = fs.existsSync(targetPath) && fs.statSync(targetPath).isDirectory()
|
||||
console.log('正在监听文件:' + targetPath)
|
||||
return {
|
||||
name: 'file-watcher-plugin',
|
||||
configureServer(server) {
|
||||
server.watcher.add(path.resolve(file))
|
||||
|
||||
server.watcher.on('change', (filePath: string) => {
|
||||
if (filePath === path.resolve(file)) {
|
||||
if (debounceTimer) clearTimeout(debounceTimer)
|
||||
debounceTimer = setTimeout(() => {
|
||||
configureServer(server) {
|
||||
// 添加要监听的目标(文件或文件夹)
|
||||
server.watcher.add(targetPath)
|
||||
|
||||
// 处理文件/文件夹变化的通用函数
|
||||
const handleChange = (filePath: string, eventType: 'add' | 'change' | 'unlink') => {
|
||||
if (isDir && !filePath.startsWith(targetPath)) {
|
||||
return
|
||||
}
|
||||
if (!isDir && filePath !== targetPath) {
|
||||
return
|
||||
}
|
||||
// 防抖处理
|
||||
if (debounceTimer) {
|
||||
clearTimeout(debounceTimer)
|
||||
}
|
||||
|
||||
debounceTimer = setTimeout(async () => {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf-8')
|
||||
fn(content)
|
||||
let content: string | undefined
|
||||
if (!isDir) {
|
||||
content = fs.readFileSync(filePath, 'utf-8')
|
||||
}
|
||||
fn(filePath, content, eventType)
|
||||
} catch (error) {
|
||||
console.error('文件变化处理失败:', error)
|
||||
console.error('处理文件变化时出错:', error)
|
||||
}
|
||||
}, delay)
|
||||
}
|
||||
|
||||
if (isDir) {
|
||||
// 监听文件新增
|
||||
server.watcher.on('add', (filePath) => {
|
||||
handleChange(filePath, 'add')
|
||||
})
|
||||
|
||||
// 监听文件删除
|
||||
server.watcher.on('unlink', (filePath) => {
|
||||
handleChange(filePath, 'unlink')
|
||||
})
|
||||
}
|
||||
|
||||
// 监听文件修改
|
||||
server.watcher.on('change', (filePath) => {
|
||||
handleChange(filePath, 'change')
|
||||
})
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ interface IconfontJson {
|
|||
}
|
||||
|
||||
export default function iconfontProcess(outPath: string) {
|
||||
return function (content: string) {
|
||||
const json = JSON.parse(content) as IconfontJson
|
||||
return function (filePath: string, content?: string, eventType?: 'add' | 'change' | 'unlink') {
|
||||
console.log(filePath, content, eventType)
|
||||
const json = JSON.parse(content!) as IconfontJson
|
||||
const names = json.glyphs.map(glyph => glyph.font_class)
|
||||
const dtsFile = outPath + '/iconfont.d.ts'
|
||||
console.log('正在生成文件:', dtsFile)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const paramsSerializer = (params: any) => {
|
|||
Toast.error(r?.message ?? '操作失败')
|
||||
} */
|
||||
const errHandler = throttle(500, (r?: R) => {
|
||||
Toast.error(r?.message ?? '操作失败')
|
||||
Toast.error(r?.message ?? '服务器错误')
|
||||
})
|
||||
/**
|
||||
* axios 实例
|
||||
|
|
|
|||
|
|
@ -136,10 +136,26 @@ export function pretty(date: DateTime<true | false> | Date | number | string) {
|
|||
return '现在'
|
||||
}
|
||||
|
||||
export function endOfMonth(date?: DateTime<true | false>) {
|
||||
if (date == null) {
|
||||
return date = now()
|
||||
}
|
||||
return date.endOf('month')
|
||||
}
|
||||
|
||||
export function beginOfMonth(date?: DateTime<true | false>) {
|
||||
if (date == null) {
|
||||
return date = now()
|
||||
}
|
||||
return date.startOf('month')
|
||||
}
|
||||
|
||||
export default {
|
||||
now,
|
||||
parse,
|
||||
format,
|
||||
pretty,
|
||||
FMT,
|
||||
endOfMonth,
|
||||
beginOfMonth,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,21 +82,6 @@ declare global {
|
|||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type {
|
||||
Component,
|
||||
ComponentPublicInstance,
|
||||
ComputedRef,
|
||||
DirectiveBinding,
|
||||
ExtractDefaultPropTypes,
|
||||
ExtractPropTypes,
|
||||
ExtractPublicPropTypes,
|
||||
InjectionKey,
|
||||
PropType,
|
||||
Ref,
|
||||
MaybeRef,
|
||||
MaybeRefOrGetter,
|
||||
VNode,
|
||||
WritableComputedRef
|
||||
} from 'vue'
|
||||
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
|
||||
import('vue')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ declare module 'vue' {
|
|||
IxFormItem: typeof import('@idux/components/form')['IxFormItem']
|
||||
IxFormWrapper: typeof import('@idux/components/form')['IxFormWrapper']
|
||||
IxIcon: typeof import('@idux/components/icon')['IxIcon']
|
||||
IxImage: typeof import('@idux/components/image')['IxImage']
|
||||
IxInput: typeof import('@idux/components/input')['IxInput']
|
||||
IxInputNumber: typeof import('@idux/components/input-number')['IxInputNumber']
|
||||
IxLayoutSiderTrigger: typeof import('@idux/components/layout')['IxLayoutSiderTrigger']
|
||||
|
|
@ -44,6 +45,7 @@ declare module 'vue' {
|
|||
IxTable: typeof import('@idux/components/table')['IxTable']
|
||||
IxTabs: typeof import('@idux/components/tabs')['IxTabs']
|
||||
IxTag: typeof import('@idux/components/tag')['IxTag']
|
||||
IxTagGroup: typeof import('@idux/components/tag')['IxTagGroup']
|
||||
IxTooltip: typeof import('@idux/components/tooltip')['IxTooltip']
|
||||
IxTreeSelect: typeof import('@idux/components/tree-select')['IxTreeSelect']
|
||||
IxUpload: typeof import('@idux/components/upload')['IxUpload']
|
||||
|
|
|
|||
|
|
@ -63,6 +63,13 @@ defineExpose({
|
|||
<p class="detail-item img-card"><span class="img-title">出出场车头照</span><img :src="data.outFrontPhoto" alt="出场前"></p>
|
||||
<p class="detail-item img-card"><span class="img-title">出场车身照</span><img :src="data.outBodyPhoto" alt="出场后"></p>
|
||||
</div>
|
||||
<div class="dispose-recode-detail-img-title">装车照片</div>
|
||||
<div v-if="data.tspPhotos == null || data.tspPhotos.length === 0">
|
||||
<IxEmpty/>
|
||||
</div>
|
||||
<div v-else class="dispose-recode-detail-img">
|
||||
<p v-for="tspPhoto in data.tspPhotos" class="detail-item img-card"><span class="img-title"></span><img :src="tspPhoto" alt="装车照片"></p>
|
||||
</div>
|
||||
|
||||
<template #footer="{ cancel:_, ok }">
|
||||
<IxButton mode="primary" @click="ok">确定</IxButton>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ declare global {
|
|||
inBodyPhoto: string
|
||||
outFrontPhoto: string
|
||||
outBodyPhoto: string
|
||||
tspPhotos?: string[]
|
||||
}
|
||||
|
||||
interface SearchParam {
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@
|
|||
</IxButtonGroup>
|
||||
</template>
|
||||
</IxTable>
|
||||
<IxRow justify="end">
|
||||
<!--<IxRow justify="end">
|
||||
<IxPagination v-model:pageIndex="pagination.current" v-model:pageSize="pagination.size" :total="pagination.total"
|
||||
class="pagination"
|
||||
show-quick-jumper
|
||||
show-size-changer show-total @change="pagingChangeHandler"/>
|
||||
</IxRow>
|
||||
</IxRow>-->
|
||||
<IxModal v-model:visible="visibleDialog" title="删除提醒" type="confirm" @ok="confirmDelHandler">
|
||||
<p>是否删除已选数据?</p>
|
||||
</IxModal>
|
||||
|
|
@ -59,6 +59,7 @@ import MenuApi from '@/pages/sys/menus/menu-api.ts'
|
|||
import { TreeSelectNode } from '@idux/components/tree-select/src/types'
|
||||
import Toast from '@/components/toast'
|
||||
import { useMenuDetailStore } from '@/pages/sys/menus/menu-detail/menu-detail-store.ts'
|
||||
import Iconfont from '@/components/iconfont/Iconfont.vue'
|
||||
|
||||
const searchForm = useFormGroup<MenuTypes.SearchForm>({
|
||||
title: [ '' ],
|
||||
|
|
@ -67,11 +68,6 @@ const searchForm = useFormGroup<MenuTypes.SearchForm>({
|
|||
const visibleDialog = ref(false)
|
||||
const tableSpin = ref(false)
|
||||
const selectedRowKeys = ref<VKey[]>([])
|
||||
const pagination = reactive<G.Pagination>({
|
||||
current: 1,
|
||||
size: 100,
|
||||
total: 0,
|
||||
})
|
||||
const datasource = ref<TreeSelectNode[]>()
|
||||
|
||||
const columns: TableColumn<MenuTypes.SysMenu>[] = [
|
||||
|
|
@ -96,6 +92,9 @@ const columns: TableColumn<MenuTypes.SysMenu>[] = [
|
|||
{
|
||||
title: '图标',
|
||||
dataKey: 'icon',
|
||||
customCell({value}: { value: string; record: MenuTypes.SysMenu; rowIndex: number }) {
|
||||
return h(Iconfont, {name: value as IconfontTypes.name})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '路径',
|
||||
|
|
@ -180,12 +179,9 @@ function searchHandler() {
|
|||
|
||||
function pageList() {
|
||||
tableSpin.value = true
|
||||
MenuApi.pageList(searchForm.getValue(), {...pagination})
|
||||
MenuApi.list(searchForm.getValue())
|
||||
.then(res => {
|
||||
pagination.current = res.data.current
|
||||
pagination.size = res.data.size
|
||||
pagination.total = res.data.total
|
||||
datasource.value = colls.toTree(res.data.records.map(it => {
|
||||
datasource.value = colls.toTree(res.data.map(it => {
|
||||
return {
|
||||
key: it.id,
|
||||
...it
|
||||
|
|
@ -197,10 +193,6 @@ function pageList() {
|
|||
})
|
||||
}
|
||||
|
||||
function pagingChangeHandler() {
|
||||
pageList()
|
||||
}
|
||||
|
||||
function del(...recode: { id: string }[]) {
|
||||
const toastId = Toast.loading('正在提交')
|
||||
MenuApi.del(recode.map(it => it.id))
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ export default {
|
|||
paging(data: MenuTypes.SearchForm & G.PageParam) {
|
||||
return get<G.PageResult<MenuTypes.SysMenu>>('/sys_menu/page_list', data)
|
||||
},
|
||||
list(pid: string | null = null) {
|
||||
return get<MenuTypes.SysMenu[]>('/sys_menu/list', {pid: pid})
|
||||
list(data?: MenuTypes.SearchForm | null) {
|
||||
return get<MenuTypes.SysMenu[]>('/sys_menu/list', data)
|
||||
},
|
||||
detail(id: string) {
|
||||
return get<MenuTypes.SysMenu>('/sys_menu/detail', {id})
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ import {
|
|||
TableColumnSelectable
|
||||
} from '@idux/components/table'
|
||||
import { TablePagination } from '@idux/components/table/src/types'
|
||||
import Iconfont from '@/components/iconfont/Iconfont.vue'
|
||||
|
||||
interface IconData {
|
||||
name: string
|
||||
|
|
@ -120,9 +121,9 @@ const columns: TableColumn<IconData>[] = [
|
|||
{
|
||||
title: '图标',
|
||||
dataKey: 'name',
|
||||
/* customCell: ({record}: { record: IconData }) => {
|
||||
return h(Iconfont, {name: record.name})
|
||||
} */
|
||||
customCell: ({record}: { record: IconData }) => {
|
||||
return h(Iconfont, {name: record.name as IconfontTypes.name})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '名称',
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ declare global {
|
|||
children?: SysMenu[]
|
||||
}
|
||||
|
||||
type SearchForm = Partial<Pick<SysMenu, 'title' | 'routeName'>>
|
||||
type SearchForm = Partial<Pick<SysMenu, 'title' | 'routeName' | 'pid'>>
|
||||
type MenuForm = Pick<SysMenu, 'pid' | 'menuCategory' | 'title' | 'sort' | 'routeName' | 'sn' | 'icon'>
|
||||
type AddForm = Pick<SysMenu, 'pid' | 'menuCategory' | 'title' | 'sort' | 'routeName' | 'sn'>
|
||||
type ModifyForm = Pick<SysMenu, 'id' | 'pid' | 'menuCategory' | 'title' | 'sort' | 'routeName'>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,391 @@
|
|||
<script lang="ts" setup>
|
||||
import times, { FMT } from '@/common/utils/times.ts'
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
TableColumn,
|
||||
TableColumnSelectable
|
||||
} from '@idux/components/table'
|
||||
import { TablePagination } from '@idux/components/table/src/types'
|
||||
import TspApi from '@/pages/tsp/tsp-api.ts'
|
||||
import { useFormGroup, } from '@idux/cdk'
|
||||
import TspPhotoApi from '@/pages/tsp-photo/tsp-photo-api.ts'
|
||||
|
||||
const weekday = [ '周一', '周二', '周三', '周四', '周五', '周六', '周日' ]
|
||||
|
||||
interface DayType {
|
||||
year: number
|
||||
month: number
|
||||
day: number
|
||||
}
|
||||
|
||||
const visible = ref(false)
|
||||
const selectedRowKeys = ref<string[]>([])
|
||||
const tspPhotoForm = useFormGroup<TspPhotoTypes.TspPhotoSearchParam>({
|
||||
tspId: [ undefined ],
|
||||
pointName: [ undefined ],
|
||||
month: [ new Date() ],
|
||||
day: [ 0 ],
|
||||
uploadDate: [ times.format(new Date(), FMT.date) ],
|
||||
})
|
||||
const days = ref<Array<Array<DayType | null>>>([])
|
||||
|
||||
function renderCalendar(value: Date = new Date()) {
|
||||
const beginOfMonth = times.beginOfMonth(times.parse(value))
|
||||
const endOfMonth = times.endOfMonth(times.parse(value))
|
||||
|
||||
const firstDayIndex = beginOfMonth.weekday - 1
|
||||
|
||||
const count = (7 - (endOfMonth.day + firstDayIndex) % 7) + (endOfMonth.day + firstDayIndex)
|
||||
const days_: Array<Array<DayType | null>> = []
|
||||
|
||||
let temp: Array<DayType | null> = []
|
||||
for (let i = 0; i < count; i++) {
|
||||
if (i < firstDayIndex) {
|
||||
temp.push(null)
|
||||
} else if (i >= firstDayIndex && i < firstDayIndex + endOfMonth.day) {
|
||||
temp.push({
|
||||
year: beginOfMonth.year,
|
||||
month: beginOfMonth.month,
|
||||
day: i - firstDayIndex + 1
|
||||
})
|
||||
|
||||
} else {
|
||||
temp.push(null)
|
||||
}
|
||||
if (temp.length === 7) {
|
||||
days_.push(temp)
|
||||
temp = []
|
||||
}
|
||||
}
|
||||
days.value = days_
|
||||
}
|
||||
|
||||
function disabledDate(date: Date) {
|
||||
return times.parse(date).month > times.now().month
|
||||
}
|
||||
|
||||
const datasource = ref<TspTypes.TspData[]>()
|
||||
|
||||
const selectableColumn = reactive<TableColumnSelectable<TspTypes.TspData>>({
|
||||
type: 'selectable',
|
||||
align: 'center',
|
||||
multiple: false,
|
||||
showIndex: false,
|
||||
trigger: 'click',
|
||||
onChange: (selectedKeys) => {
|
||||
if (selectedKeys.length === 0) {
|
||||
const value = tspPhotoForm.get('tspId')?.getValue()
|
||||
if (value != null) {
|
||||
selectedRowKeys.value = [ value ]
|
||||
} else {
|
||||
tspPhotoForm.get('tspId')?.setValue('')
|
||||
tspPhotoForm.get('pointName')?.setValue('')
|
||||
}
|
||||
return
|
||||
}
|
||||
const data = datasource.value?.find(item => item.id === (selectedKeys[0] as string))
|
||||
tspPhotoForm.get('tspId')?.setValue(selectedKeys[0] as string)
|
||||
tspPhotoForm.get('pointName')?.setValue(data?.pointName)
|
||||
},
|
||||
})
|
||||
const tableSpin = ref(false)
|
||||
|
||||
const pagination = reactive<TablePagination>({
|
||||
pageIndex: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
size: 'sm',
|
||||
showTotal: true,
|
||||
onChange(pageIndex: number, pageSize: number) {
|
||||
pagination.pageIndex = pageIndex
|
||||
pagination.pageSize = pageSize
|
||||
searchHandler()
|
||||
}
|
||||
})
|
||||
|
||||
function searchHandler() {
|
||||
tableSpin.value = true
|
||||
TspApi.paging({
|
||||
current: pagination.pageIndex ?? 1,
|
||||
size: pagination.pageSize ?? 10,
|
||||
})
|
||||
.then(res => {
|
||||
pagination.pageIndex = res.data.current
|
||||
pagination.pageSize = res.data.size
|
||||
pagination.total = res.data.total
|
||||
datasource.value = res.data.records
|
||||
})
|
||||
.finally(() => {
|
||||
tableSpin.value = false
|
||||
})
|
||||
}
|
||||
|
||||
const photoUploadStatus = ref<TspPhotoTypes.ObtainStatusResult>({})
|
||||
|
||||
const columns: TableColumn<TspTypes.TspData>[] = [
|
||||
selectableColumn,
|
||||
{
|
||||
title: '名称',
|
||||
dataKey: 'pointName',
|
||||
customCell: 'pointName'
|
||||
},
|
||||
{
|
||||
title: '所属街道',
|
||||
dataKey: 'streetName',
|
||||
},
|
||||
{
|
||||
title: '所属小区',
|
||||
dataKey: 'microdistrict',
|
||||
},
|
||||
{
|
||||
title: '所属物业',
|
||||
dataKey: 'propertyManagement'
|
||||
},
|
||||
]
|
||||
|
||||
watch(visible, (newVal) => {
|
||||
if (newVal) {
|
||||
searchHandler()
|
||||
}
|
||||
})
|
||||
|
||||
const computedTitle = () => {
|
||||
const uploadDate = tspPhotoForm.get('uploadDate')?.getValue()
|
||||
const pointName = tspPhotoForm.get('pointName')?.getValue()
|
||||
return uploadDate == null || pointName == null ? '图片列表' : pointName + ' ' + times.format(times.parse(uploadDate, FMT.date), FMT.date_zh) + '上传的图片'
|
||||
}
|
||||
const photoListTitle = ref<string>('图片列表')
|
||||
|
||||
const photoList = ref<string[]>()
|
||||
|
||||
|
||||
tspPhotoForm.get('tspId')?.watchValue(() => {
|
||||
TspPhotoApi.obtainStatus(tspPhotoForm.getValue()).then(res => {
|
||||
photoUploadStatus.value = res.data
|
||||
})
|
||||
})
|
||||
tspPhotoForm.get('month')?.watchValue((month) => {
|
||||
tspPhotoForm.get('day')?.setValue(0)
|
||||
if (month == null) {
|
||||
return
|
||||
}
|
||||
tspPhotoForm.get('uploadDate')?.setValue(times.format(times.parse(month), FMT.date))
|
||||
|
||||
TspPhotoApi.obtainStatus(tspPhotoForm.getValue()).then(res => {
|
||||
photoUploadStatus.value = res.data
|
||||
})
|
||||
})
|
||||
|
||||
function onClickDate(day: DayType) {
|
||||
tspPhotoForm.get('day')?.setValue(day.day)
|
||||
tspPhotoForm.get('uploadDate')?.setValue(`${day.year}-${day.month < 10 ? '0' + day.month : day.month}-${day.day < 10 ? '0' + day.day : day.day}`)
|
||||
photoListTitle.value = computedTitle()
|
||||
TspPhotoApi.listPhoto(tspPhotoForm.getValue())
|
||||
.then(res => {
|
||||
photoList.value = res.data?.photos ?? []
|
||||
})
|
||||
}
|
||||
|
||||
const files = ref([])
|
||||
onMounted(() => {
|
||||
renderCalendar()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="tsp-photo-wrapper">
|
||||
<div class="calendar-wrapper">
|
||||
<div class="calendar-title">
|
||||
<IxForm :control="tspPhotoForm" class="calendar-form" layout="inline">
|
||||
<IxFormItem>
|
||||
<IxPopover v-model:visible="visible" closable header="小区列表" placement="bottom" trigger="click">
|
||||
<IxInput control="pointName" placeholder="请选择小区"/>
|
||||
<template #content>
|
||||
<IxTable v-model:selectedRowKeys="selectedRowKeys" :columns="columns" :dataSource="datasource" :pagination="pagination" :spin="tableSpin" get-key="id"/>
|
||||
</template>
|
||||
</IxPopover>
|
||||
</IxFormItem>
|
||||
<IxFormItem>
|
||||
<IxDatePicker :disabled-date="disabledDate" control="month" type="month" @change="renderCalendar"/>
|
||||
</IxFormItem>
|
||||
</IxForm>
|
||||
</div>
|
||||
<table class="calendar">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="item in weekday" :key="'weekday-' + item" class="weekday">{{ item }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in days" :key="'day-' + index">
|
||||
<td v-for="(it, i) in item" :key="'day-' + i" :class="{blank:it == null}" class="day">
|
||||
<div v-if="it != null" :class="{'active-day': it.day === tspPhotoForm.get('day')?.getValue()}" class="day-content" @click="onClickDate(it)">
|
||||
<div class="day-number">{{ it.day }}</div>
|
||||
<IxTagGroup v-if="photoUploadStatus[it.day+''] != null && photoUploadStatus[it.day+''] > 0" :gap="0" class="day-status">
|
||||
<IxTag status="success">已上传</IxTag>
|
||||
<IxTag status="success">{{ photoUploadStatus[it.day + ''] }}张</IxTag>
|
||||
</IxTagGroup>
|
||||
<IxTag v-else-if="photoUploadStatus[it.day+''] != null && photoUploadStatus[it.day+''] == 0" class="day-status" status="error">未上传</IxTag>
|
||||
<div v-else class="day-status" status="error"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="photo-wrapper">
|
||||
<div class="photo-title">
|
||||
{{ photoListTitle }}
|
||||
</div>
|
||||
<div class="photo">
|
||||
<IxImage v-for="(it,i) in photoList" :key="'photo--'+i" :src="it"/>
|
||||
</div>
|
||||
<div v-if="tspPhotoForm.get('day')?.getValue() !== 0" class="photo-bottom">
|
||||
<IxUpload v-model:files="files" action="https://run.mocky.io/v3/7564bc4f-780e-43f7-bc58-467959ae3354" dragable>
|
||||
<div class="drag-panel">
|
||||
<IxIcon class="drag-panel-icon" name="upload"></IxIcon>
|
||||
<p>拖拽上传</p>
|
||||
</div>
|
||||
<template #list>
|
||||
<IxUploadFiles type="text"/>
|
||||
</template>
|
||||
</IxUpload>
|
||||
<IxButton>提交</IxButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.tsp-photo-wrapper {
|
||||
height: 100%
|
||||
width: 100%
|
||||
display flex
|
||||
|
||||
.calendar-wrapper {
|
||||
flex 1
|
||||
padding 1rem
|
||||
box-sizing border-box
|
||||
border-right: 1px solid rgb(211, 215, 222);
|
||||
|
||||
.calendar-form {
|
||||
width 100%
|
||||
height 4rem
|
||||
|
||||
:deep(.ix-form-item):first-child {
|
||||
width 30%
|
||||
}
|
||||
|
||||
:deep(.ix-form-item):nth-child(2) {
|
||||
width 10%
|
||||
}
|
||||
}
|
||||
|
||||
.calendar {
|
||||
width 100%
|
||||
height calc(100% - 4rem);
|
||||
margin-top 1rem
|
||||
box-sizing border-box
|
||||
table-layout fixed
|
||||
|
||||
border-collapse: collapse;
|
||||
border: 1px solid rgb(211, 215, 222);
|
||||
|
||||
thead {
|
||||
height 4rem
|
||||
}
|
||||
|
||||
tbody {
|
||||
height calc(100% - 4rem);
|
||||
}
|
||||
|
||||
.day {
|
||||
border-top: 1px solid rgb(211, 215, 222);
|
||||
|
||||
&:not(.blank) {
|
||||
border: 1px solid rgb(211, 215, 222);
|
||||
}
|
||||
|
||||
|
||||
.day-content {
|
||||
cursor pointer
|
||||
|
||||
height 100%
|
||||
width 100%
|
||||
display flex
|
||||
flex-direction column
|
||||
justify-content space-around
|
||||
padding 1rem
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
&.active-day {
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.day-number {
|
||||
font-size 3rem
|
||||
font-weight bold
|
||||
}
|
||||
|
||||
.day-status {
|
||||
width 100%;
|
||||
height 20px;
|
||||
|
||||
:deep(.ix-space-item) {
|
||||
flex 1
|
||||
|
||||
& > span {
|
||||
width 100%
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.photo-wrapper {
|
||||
width 30%
|
||||
height 100%
|
||||
|
||||
display flex
|
||||
flex-direction column
|
||||
|
||||
.photo-title {
|
||||
font-size 2rem
|
||||
font-weight bold
|
||||
padding 1rem
|
||||
box-sizing border-box
|
||||
border-bottom 1px solid rgb(211, 215, 222);
|
||||
text-wrap: auto;
|
||||
word-break: break-word;
|
||||
overflow-wrap: normal;
|
||||
overflow: hidden;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.photo {
|
||||
flex 1
|
||||
width 100%;
|
||||
padding 1rem
|
||||
overflow-y auto
|
||||
display grid
|
||||
grid-template-columns repeat(2, 1fr)
|
||||
grid-auto-rows: 8rem
|
||||
gap 1rem
|
||||
align-items stretch
|
||||
|
||||
& > div {
|
||||
height: 8rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export default {
|
||||
title: '临时收纳点照片',
|
||||
component: () => import('@/pages/tsp-photo/TspPhoto.vue'),
|
||||
} as RouterTypes.PageConfig
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import { get, } from '@/common/utils/http-util.ts'
|
||||
|
||||
export default {
|
||||
save(data?: TspPhotoTypes.TspPhotoSaveParam) {
|
||||
return get<null>('/tsp_photo/save', data)
|
||||
},
|
||||
listPhoto(data?: TspPhotoTypes.TspPhotoSearchParam) {
|
||||
return get<TspPhotoTypes.TspPhotoSearchResult>('/tsp_photo/list_photo', data)
|
||||
},
|
||||
obtainStatus(data?: TspPhotoTypes.TspPhotoSearchParam) {
|
||||
return get<TspPhotoTypes.ObtainStatusResult>('/tsp_photo/obtain_status', data)
|
||||
},
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
export {}
|
||||
declare global {
|
||||
namespace TspPhotoTypes {
|
||||
interface TspPhotoSearchParam {
|
||||
tspId?: string
|
||||
pointName?: string
|
||||
month?: Date
|
||||
day?: number
|
||||
uploadDate?: string
|
||||
}
|
||||
|
||||
interface TspPhotoSearchResult {
|
||||
photos?: string[]
|
||||
}
|
||||
|
||||
interface ObtainStatusResult {
|
||||
[key: string]: number | undefined | null
|
||||
}
|
||||
|
||||
interface TspPhotoSaveParam {
|
||||
tspId?: string
|
||||
uploadDate?: string
|
||||
photos?: string[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,8 +21,8 @@ declare global {
|
|||
}
|
||||
|
||||
interface SearchParam {
|
||||
pointName: string
|
||||
status: 'ZhengChang' | 'FenZhengChang' | ''
|
||||
pointName?: string
|
||||
status?: 'ZhengChang' | 'FenZhengChang' | ''
|
||||
}
|
||||
|
||||
interface StatisticsResult {
|
||||
|
|
|
|||
Loading…
Reference in New Issue