提交 b0e592e5 authored 作者: lidongxu's avatar lidongxu

Merge branch 'dev'

...@@ -16,9 +16,11 @@ VITE_APP_REDIRECT_URL = 'http://localhost:8085' ...@@ -16,9 +16,11 @@ VITE_APP_REDIRECT_URL = 'http://localhost:8085'
# 积木报表服务地址 # 积木报表服务地址
VITE_APP_REPORT_URL = 'https://sfa-qa.wxl66.cn' VITE_APP_REPORT_URL = 'https://sfa-qa.wxl66.cn'
# 积木报表预览地址 # 积木报表预览地址
VITE_APP_REPORT_PREVIEW_URL = 'https://sfa-qa.wxl66.cn/report/jmreport/view' VITE_APP_REPORT_PREVIEW_URL = '/report/jmreport/view'
# 积木报表分享预览地址
VITE_APP_REPORT_SHARE_PREVIEW_URL = '/report'
# 积木报表编辑地址 # 积木报表编辑地址
VITE_APP_REPORT_EDIT_URL = 'https://sfa-qa.wxl66.cn/report/jmreport/index' VITE_APP_REPORT_EDIT_URL = '/report/jmreport/index'
# 模板表格 # 模板表格
VITE_APP_PLAN_TEMPLATE_EXCEL = 'https://link-promotion.oss-cn-shanghai.aliyuncs.com/file/%E6%96%B0%E5%A2%9E%E6%88%96%E4%BF%AE%E6%94%B9%E8%AE%A1%E5%88%92-%E6%A8%A1%E6%9D%BF4.0.xlsx' VITE_APP_PLAN_TEMPLATE_EXCEL = 'https://link-promotion.oss-cn-shanghai.aliyuncs.com/file/%E6%96%B0%E5%A2%9E%E6%88%96%E4%BF%AE%E6%94%B9%E8%AE%A1%E5%88%92-%E6%A8%A1%E6%9D%BF4.0.xlsx'
...@@ -16,6 +16,8 @@ VITE_APP_REDIRECT_URL = 'https://sfa.wxl66.cn/link/' ...@@ -16,6 +16,8 @@ VITE_APP_REDIRECT_URL = 'https://sfa.wxl66.cn/link/'
VITE_APP_REPORT_URL = 'https://sfa.wxl66.cn' VITE_APP_REPORT_URL = 'https://sfa.wxl66.cn'
# 积木报表预览地址 # 积木报表预览地址
VITE_APP_REPORT_PREVIEW_URL = '/report/jmreport/view' VITE_APP_REPORT_PREVIEW_URL = '/report/jmreport/view'
# 积木报表分享预览地址
VITE_APP_REPORT_SHARE_PREVIEW_URL = '/report'
# 积木报表编辑地址 # 积木报表编辑地址
VITE_APP_REPORT_EDIT_URL = '/report/jmreport/index' VITE_APP_REPORT_EDIT_URL = '/report/jmreport/index'
......
...@@ -15,6 +15,8 @@ VITE_APP_REDIRECT_URL = 'https://sfa-qa.wxl66.cn/' ...@@ -15,6 +15,8 @@ VITE_APP_REDIRECT_URL = 'https://sfa-qa.wxl66.cn/'
VITE_APP_REPORT_URL = 'https://sfa-qa.wxl66.cn' VITE_APP_REPORT_URL = 'https://sfa-qa.wxl66.cn'
# 积木报表预览地址 # 积木报表预览地址
VITE_APP_REPORT_PREVIEW_URL = '/report/jmreport/view' VITE_APP_REPORT_PREVIEW_URL = '/report/jmreport/view'
# 积木报表分享预览地址
VITE_APP_REPORT_SHARE_PREVIEW_URL = '/report'
# 积木报表编辑地址 # 积木报表编辑地址
VITE_APP_REPORT_EDIT_URL = '/report/jmreport/index' VITE_APP_REPORT_EDIT_URL = '/report/jmreport/index'
......
...@@ -25,6 +25,7 @@ export * from './monitor/online' ...@@ -25,6 +25,7 @@ export * from './monitor/online'
export * from './monitor/server' export * from './monitor/server'
export * from './promotion/plan' export * from './promotion/plan'
export * from './promotion/task' export * from './promotion/task'
export * from './scm/logistics_receipt'
export * from './system/dict/data' export * from './system/dict/data'
export * from './system/dict/type' export * from './system/dict/type'
export * from './system/attendance' export * from './system/attendance'
......
...@@ -54,3 +54,22 @@ export function importReportAPI(data) { ...@@ -54,3 +54,22 @@ export function importReportAPI(data) {
} }
}) })
} }
// 查询分享报表连接
export function selShareReportAPI(params) {
return request({
url: `/report/jmreport/share/queryJurisdiction`,
params
})
}
// 创建/编辑分享链接参数
export function addOrEditShareReportAPI(data) {
return request({
url: `/report/jmreport/share/addAndEdit`,
method: 'POST',
data
})
}
import request from '@/utils/request'
// 勤策发货单列表查询
export const getLogisticsReceiptListAPI = (params) => {
return request({
url: '/bi/ordersent/query/page',
params
})
}
// 勤策发货单-回单照片是否完整&物流状态设置
export const setLogisticsReceiptStatusAPI = (data) => {
return request({
url: '/bi/ordersent/core/update',
method: 'PUT',
data
})
}
...@@ -78,8 +78,8 @@ const handleClose = () => { ...@@ -78,8 +78,8 @@ const handleClose = () => {
}; };
const handleViewDetail = () => { const handleViewDetail = () => {
// 跳转到飞书文档查看版本更新详情文档 // 跳转到飞书文档查看版本更新详情文档(打开新标签页面)
// emit('viewDetail'); window.open('https://wangxiaolu.feishu.cn/docx/MJf8d6Rrsood6IxnIsKch1clnwc', '_blank')
}; };
const handleConfirm = () => { const handleConfirm = () => {
......
...@@ -105,8 +105,9 @@ const showQuit = !window.h5sdk; // 判断飞书客户端内,则不显示退出 ...@@ -105,8 +105,9 @@ const showQuit = !window.h5sdk; // 判断飞书客户端内,则不显示退出
const showVersionNoticeVisible = ref(false) // 判断版本通知是否出现 const showVersionNoticeVisible = ref(false) // 判断版本通知是否出现
const nowVersion = ref('') // 当前最新版本 const nowVersion = ref('') // 当前最新版本
// 判断是否有新版本出现 // 判断是否有新版本出现(监听 pinia 值的变化)
onMounted(() => { watch(() => versionStore.version, (newVal, oldVal) => {
console.log('versionStore.version', versionStore.version)
const oldVersion = proxy.$cache.local.get('version') const oldVersion = proxy.$cache.local.get('version')
const versionObj = versionStore.version[0] const versionObj = versionStore.version[0]
nowVersion.value = versionObj.version nowVersion.value = versionObj.version
...@@ -114,6 +115,7 @@ onMounted(() => { ...@@ -114,6 +115,7 @@ onMounted(() => {
handleVersionList() handleVersionList()
} }
}) })
// 展示版本通知弹框 // 展示版本通知弹框
const showVersionFn = () => { const showVersionFn = () => {
handleVersionList() handleVersionList()
......
...@@ -36,23 +36,24 @@ router.beforeEach((to, from, next) => { ...@@ -36,23 +36,24 @@ router.beforeEach((to, from, next) => {
useUserStore().getInfo().then(() => { useUserStore().getInfo().then(() => {
isRelogin.show = false isRelogin.show = false
usePermissionStore().generateRoutes().then(accessRoutes => { usePermissionStore().generateRoutes().then(accessRoutes => {
// 生成可访问路由表 // 获取版本信息
accessRoutes.forEach(route => { useVersionStore().getVersion().then((res) => {
if (!isHttp(route.path)) { // 生成可访问路由表
router.addRoute(route) accessRoutes.forEach(route => {
} if (!isHttp(route.path)) {
router.addRoute(route)
}
})
next({ ...to, replace: true })
}) })
next({ ...to, replace: true })
}) })
}).catch(err => { }).catch(err => {
useUserStore().logOut().then(() => { useUserStore().logOut().then(() => {
ElMessage.error(err) ElMessage.error(err)
next({ path: '/' }) next({ path: '/' })
}) })
}) })
// 获取版本信息
useVersionStore().getVersion()
} else { } else {
next() next()
} }
......
...@@ -14,6 +14,7 @@ export function useDict(...args) { ...@@ -14,6 +14,7 @@ export function useDict(...args) {
res.value[dictType] = dicts; res.value[dictType] = dicts;
} else { } else {
getDicts(dictType).then(resp => { getDicts(dictType).then(resp => {
console.log('字典数据', resp.data)
res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass })) res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass }))
useDictStore().setDict(dictType, res.value[dictType]); useDictStore().setDict(dictType, res.value[dictType]);
}) })
......
...@@ -60,7 +60,9 @@ ...@@ -60,7 +60,9 @@
<template #default="{ row }"> <template #default="{ row }">
<div> <div>
<svg-icon icon-class="bg-document"></svg-icon> <svg-icon icon-class="bg-document"></svg-icon>
<span style="margin-left: 10px">{{ row.name }}</span> <el-link :href="getReportPreviewUrl(row)"
target="_blank"
style="margin-left: 10px">{{ row.name }}</el-link>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
...@@ -69,12 +71,12 @@ ...@@ -69,12 +71,12 @@
align="left" align="left"
width="200"> width="200">
<template #default="scope"> <template #default="scope">
<xl-tool-tip content="预览报表" <xl-tool-tip content="分享报表"
placement="top"> placement="top">
<el-button link <el-button link
type="primary" type="primary"
icon="View" icon="Share"
@click="handlePreview(scope.row)"></el-button> @click="handleShare(scope.row)"></el-button>
</xl-tool-tip> </xl-tool-tip>
<xl-tool-tip content="修改" <xl-tool-tip content="修改"
placement="top"> placement="top">
...@@ -108,6 +110,50 @@ ...@@ -108,6 +110,50 @@
v-model:limit="queryParams.pageSize" v-model:limit="queryParams.pageSize"
@pagination="getReportList" /> @pagination="getReportList" />
</el-col> </el-col>
<!-- 新增/编辑分享弹窗 -->
<el-dialog title="创建分享链接"
v-model="dialogVisible">
<div v-if="shareReportUrl">
<el-form-item label="分享链接">
<el-input v-model="shareReportUrl"
style="width: 80%; margin-right: 20px;"
placeholder="分享链接" />
<el-button type="primary"
v-copyText="shareReportUrl"
v-copyText:callback="copyTextSuccess">复制链接剪切板</el-button>
</el-form-item>
</div>
<div v-else>
<el-form label-width="180px"
v-model="shareForm">
<el-form-item label="过期时间">
<el-radio-group v-model="shareForm.termOfValidity">
<el-radio value="1">永久有效</el-radio>
<el-radio value="2">7天</el-radio>
<el-radio value="3">1天</el-radio>
</el-radio-group>
</el-form-item>
<!-- <el-form-item label="是否开启密码">
<el-radio-group v-model="shareForm.isPasswordEnabled">
<el-radio label="否">否</el-radio>
<el-radio label="是">是</el-radio>
</el-radio-group>
</el-form-item> -->
<!-- <el-form-item label="是否检验分享token">
<el-switch v-model="shareForm.isCheckToken" />
</el-form-item> -->
</el-form>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary"
@click="handleConfirm">确认</el-button>
</span>
</template>
</el-dialog>
</el-row> </el-row>
</div> </div>
</div> </div>
...@@ -115,12 +161,14 @@ ...@@ -115,12 +161,14 @@
<script setup> <script setup>
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { getReportFolderStructureAPI, getDesignReportListAPI, deleteReportAPI, copyReportAPI, addReportAPI, importReportAPI } from '@/api' import { getReportFolderStructureAPI, getDesignReportListAPI, deleteReportAPI, copyReportAPI, addReportAPI, importReportAPI, selShareReportAPI, addOrEditShareReportAPI } from '@/api'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const userStore = useUserStore() const userStore = useUserStore()
const reportBaseDomain = import.meta.env.VITE_APP_REPORT_URL // 基础域名
const reportViewURL = import.meta.env.VITE_APP_REPORT_PREVIEW_URL // 预览 const reportViewURL = import.meta.env.VITE_APP_REPORT_PREVIEW_URL // 预览
const reportShareViewURL = import.meta.env.VITE_APP_REPORT_SHARE_PREVIEW_URL // 分享预览
const reportEditURL = import.meta.env.VITE_APP_REPORT_EDIT_URL // 新增/编辑 const reportEditURL = import.meta.env.VITE_APP_REPORT_EDIT_URL // 新增/编辑
/************ 文件夹分组 ********************/ /************ 文件夹分组 ********************/
...@@ -187,13 +235,16 @@ const getReportList = async () => { ...@@ -187,13 +235,16 @@ const getReportList = async () => {
total.value = res.result.total total.value = res.result.total
} }
getReportList() getReportList()
// 报表预览地址
const getReportPreviewUrl = (row) => {
return `${reportBaseDomain}${reportShareViewURL}${row.shareViewUrl}`
}
/********* 报表功能按钮 ***********/ /********* 报表功能按钮 ***********/
// 新建报表 // 新建报表
const handleAdd = async () => { const handleAdd = async () => {
const res = await addReportAPI() const res = await addReportAPI()
window.open(`${reportEditURL}/${res.result.id}?menuType=${queryParams.reportType}&token=${getToken()}&tenantId=${userStore.$state.userInfo.deptId}`) window.open(`${reportBaseDomain}${reportEditURL}/${res.result.id}?menuType=${queryParams.reportType}&token=${getToken()}&tenantId=${userStore.$state.userInfo.deptId}`)
} }
// 导入报表 // 导入报表
const handleImport = () => { const handleImport = () => {
...@@ -206,19 +257,68 @@ const handleImport = () => { ...@@ -206,19 +257,68 @@ const handleImport = () => {
formData.append('type', queryParams.reportType) formData.append('type', queryParams.reportType)
const res = await importReportAPI(formData) const res = await importReportAPI(formData)
proxy.$modal.msgSuccess(res.result) proxy.$modal.msgSuccess(res.result)
getReportList() getReportList()
}).catch(err => { }).catch(err => {
proxy.$modal.msgError(err) proxy.$modal.msgError(err)
}) })
} }
// 预览报表
const handlePreview = (row) => { // 分享报表
window.open(`${reportViewURL}/${row.id}?token=${getToken()}&tenantId=${userStore.$state.userInfo.deptId}`) const shareReportUrl = ref('') // 分享报表地址链接
const dialogVisible = ref(false)
const nowShareRow = ref(null) // 当前分享报表数据对象
const shareForm = reactive({
termOfValidity: '1', // 1:永久有效 2:7天 3:1天
// isPasswordEnabled: '否',
verifyShareToken: true
})
const handleShare = async (row) => {
const res = await selShareReportAPI({
reportId: row.id
})
shareReportUrl.value = res.result?.previewUrl ? reportBaseDomain + reportShareViewURL + res.result?.previewUrl : ''
nowShareRow.value = row
dialogVisible.value = true
}
// 确认分享
const handleConfirm = async () => {
if (shareReportUrl.value) {
dialogVisible.value = false
return
}
const res = await addOrEditShareReportAPI({
id: nowShareRow.value.id,
lastUpdateTime: new Date().getTime(),
previewLock: "",
previewLockStatus: "0",
previewUrl: "",
reportId: nowShareRow.value.id,
shareToken: Math.random().toString(36).substring(2),
status: "0",
termOfValidity: shareForm.termOfValidity,
verifyShareToken: shareForm.verifyShareToken ? '1' : '0'
})
shareReportUrl.value = reportBaseDomain + reportShareViewURL + res.result?.previewUrl
// 将分享链接复制到剪贴板
const input = document.createElement('input')
input.setAttribute('value', shareReportUrl.value)
document.body.appendChild(input)
input.select()
document.execCommand('copy')
document.body.removeChild(input)
proxy.$modal.msgSuccess('链接已复制到剪切板')
dialogVisible.value = false
}
// 点击分享地址复制
function copyTextSuccess() {
proxy.$modal.msgSuccess('链接已复制到剪切板')
} }
// 修改报表 // 修改报表
const handleEdit = (row) => { const handleEdit = (row) => {
window.open(`${reportEditURL}/${row.id}?token=${getToken()}&tenantId=${userStore.$state.userInfo.deptId}`) window.open(`${reportBaseDomain}${reportEditURL}/${row.id}?token=${getToken()}&tenantId=${userStore.$state.userInfo.deptId}`)
} }
// 删除报表 // 删除报表
const handleDelete = (row) => { const handleDelete = (row) => {
......
...@@ -37,18 +37,26 @@ ...@@ -37,18 +37,26 @@
prop="name" prop="name"
align="left" align="left"
sortable> sortable>
<template #default="scope"> <template #default="{ row }">
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<svg-icon icon-class="bg-document"></svg-icon> <svg-icon icon-class="bg-document"></svg-icon>
<span style="margin-left: 10px">{{ scope.row.name }}</span> <el-link :href="reportBaseDomain + reportShareViewURL + row.previewUrl"
target="_blank"
style="margin-left: 10px">{{ row.name }}</el-link>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="报表类目"
key="categoryName"
prop="categoryName"
align="left"
width="120"
sortable />
<el-table-column label="创建人" <el-table-column label="创建人"
key="createBy" key="createBy"
prop="createBy" prop="createBy"
align="left" align="left"
width="180" width="120"
sortable /> sortable />
<el-table-column label="创建时间" <el-table-column label="创建时间"
prop="createTime" prop="createTime"
...@@ -59,16 +67,31 @@ ...@@ -59,16 +67,31 @@
<span>{{ parseTime(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="是否被分享"
key="hasShare"
prop="hasShare"
align="center"
width="120"
sortable>
<!-- 使用 tag 标记颜色 -->
<template #default="{ row }">
<el-tag :type="row.hasShare === true ? 'success' : 'danger'">{{ row.hasShare === 1 ? '是' : '否' }}</el-tag>
</template>
</el-table-column>
<!-- 操作预览 --> <!-- 操作预览 -->
<el-table-column label="操作" <el-table-column label="操作"
key="operation" key="operation"
align="center" align="center"
width="180"> width="120">
<template #default="scope"> <template #default="scope">
<el-button link <el-tooltip content="复制报表地址">
type="primary" <el-button text
icon="Reading" type="primary"
@click="previewReport(scope.row)">预览</el-button> icon="Share"
v-copyText="reportBaseDomain + reportShareViewURL + scope.row.previewUrl"
v-copyText:callback="copyTextSuccess" />
</el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
...@@ -88,8 +111,12 @@ ...@@ -88,8 +111,12 @@
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
const { proxy } = getCurrentInstance()
const userStore = useUserStore() const userStore = useUserStore()
const reportViewURL = import.meta.env.VITE_APP_REPORT_PREVIEW_URL const reportBaseDomain = import.meta.env.VITE_APP_REPORT_URL // 基础域名
const reportViewURL = import.meta.env.VITE_APP_REPORT_PREVIEW_URL // 预览
const reportShareViewURL = import.meta.env.VITE_APP_REPORT_SHARE_PREVIEW_URL // 分享预览
const reportEditURL = import.meta.env.VITE_APP_REPORT_EDIT_URL // 新增/编辑
/*************** 报表列表部分 ****************/ /*************** 报表列表部分 ****************/
// 报表搜索 // 报表搜索
const showSearch = ref(true) const showSearch = ref(true)
...@@ -124,12 +151,10 @@ ...@@ -124,12 +151,10 @@
getReportList() getReportList()
// 点击某行报表 // 点击某行报表
function previewReport(row) { function copyTextSuccess() {
window.open(`${reportViewURL}/${row.id}?token=${getToken()}&tenantId=${userStore.$state.userInfo.deptId}`) proxy.$modal.msgSuccess('链接已复制到剪切板')
} }
</script> </script>
<style scoped <style scoped
lang="scss"> lang="scss"></style>
\ No newline at end of file
</style>
\ No newline at end of file
...@@ -53,10 +53,12 @@ ...@@ -53,10 +53,12 @@
prop="name" prop="name"
align="left" align="left"
sortable> sortable>
<template #default="scope"> <template #default="{ row }">
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<svg-icon icon-class="bg-document"></svg-icon> <svg-icon icon-class="bg-document"></svg-icon>
<span style="margin-left: 10px">{{ scope.row.name }}</span> <el-link :href="getReportPreviewUrl(row)"
target="_blank"
style="margin-left: 10px">{{ row.name }}</el-link>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
...@@ -212,6 +214,10 @@ ...@@ -212,6 +214,10 @@
import { selReportListAPI, selReportCategoryAPI, deptTreeSelectList, listUser, batchAuthReportAPI, selReportAuthUserListAPI } from "@/api" import { selReportListAPI, selReportCategoryAPI, deptTreeSelectList, listUser, batchAuthReportAPI, selReportAuthUserListAPI } from "@/api"
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const reportBaseDomain = import.meta.env.VITE_APP_REPORT_URL // 基础域名
const reportViewURL = import.meta.env.VITE_APP_REPORT_PREVIEW_URL // 预览
const reportShareViewURL = import.meta.env.VITE_APP_REPORT_SHARE_PREVIEW_URL // 分享预览
const reportEditURL = import.meta.env.VITE_APP_REPORT_EDIT_URL // 新增/编辑
/*************** 报表列表部分 ****************/ /*************** 报表列表部分 ****************/
// 报表搜索 // 报表搜索
...@@ -253,6 +259,10 @@ ...@@ -253,6 +259,10 @@
}) })
} }
getReportList() getReportList()
// 报表预览地址
const getReportPreviewUrl = (row) => {
return `${reportBaseDomain}${reportShareViewURL}${row.previewUrl}`
}
/**************** 分配用户 ****************/ /**************** 分配用户 ****************/
const { sys_normal_disable } = proxy.useDict("sys_normal_disable"); const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
......
...@@ -106,7 +106,8 @@ ...@@ -106,7 +106,8 @@
<el-dialog :title="photoLookInfoObj.storeName" <el-dialog :title="photoLookInfoObj.storeName"
v-model="photoDialogVisible" v-model="photoDialogVisible"
width="60%" width="60%"
draggable overflow> draggable
overflow>
<p>活动记录 ID :{{ photoLookInfoObj.id }}</p> <p>活动记录 ID :{{ photoLookInfoObj.id }}</p>
<p>活动时间 :{{ photoLookInfoObj.createDate }}</p> <p>活动时间 :{{ photoLookInfoObj.createDate }}</p>
<el-card v-for="obj in photoDialogList" <el-card v-for="obj in photoDialogList"
...@@ -115,9 +116,10 @@ ...@@ -115,9 +116,10 @@
<div class="content"> <div class="content">
<el-result :title="item.time" <el-result :title="item.time"
:sub-title="item.title" :sub-title="item.title"
v-for="item in obj.list"> v-for="item, index in obj.list">
<template #icon> <template #icon>
<el-image :src="item.photoUrl" <el-image :src="item.photoUrl"
:initial-index="index"
:preview-src-list="[...obj.list.map(o => o.photoUrl)]" /> :preview-src-list="[...obj.list.map(o => o.photoUrl)]" />
</template> </template>
</el-result> </el-result>
......
<template>
<div class="app-container">
<div class="container">
<!-- 查询表单 -->
<el-form :model="queryParams"
inline
label-position="left">
<el-row>
<el-form-item label="DD 单号查询"
prop="ddNo">
<el-input v-model="queryParams.ddNo"
clearable
placeholder="输入要查询的 DD 单号"
@input="getLogisticsReceiptList" />
</el-form-item>
<el-form-item label="安徽/北京单据编号"
prop="sentNo">
<el-input v-model="queryParams.sentNo"
clearable
placeholder="输入要查询的安徽/北京单独单号"
@input="getLogisticsReceiptList"
style="width: 250px;" />
</el-form-item>
<el-form-item label="物流公司编码"
prop="transport">
<el-input v-model="queryParams.transport"
clearable
placeholder="输入要查询的物流公司编码"
@input="getLogisticsReceiptList"
style="width: 220px;" />
</el-form-item>
<el-form-item label="快递单号"
prop="expressNo">
<el-input v-model="queryParams.expressNo"
clearable
placeholder="输入要查询的快递单号"
@input="getLogisticsReceiptList" />
</el-form-item>
<el-form-item label="订单状态"
prop="isOperateEnd">
<el-select v-model="queryParams.isOperateEnd"
placeholder="查询订单状态"
clearable
@change="getLogisticsReceiptList">
<el-option label="已完成"
value="true" />
<el-option label="未完成"
value="false" />
</el-select>
</el-form-item>
</el-row>
</el-form>
<!-- 数据表格 -->
<el-table :data="tableList"
border
style="width: 100%"
class="table-container">
<el-table-column v-for="item in columns"
:key="item.label"
:prop="item.prop"
:label="item.label"
:width="item.width"
:fixed="item.fixed"
:class-name="item.className">
<template #header="{ column }"
v-if="item.prop === 'receiptPhoto'">
<div class="header-container">
<span>{{ column.label }}</span>
<el-button @click="showPhoto = !showPhoto"
style="margin-left: 10px;">{{ showPhoto ? '隐藏' : '显示' }}图片</el-button>
</div>
</template>
<template #default="scope">
<template v-if="item.prop === 'receiptPhoto'">
<div class="receipt-photo-container"
v-if="showPhoto">
<span v-if="JSON.parse(scope.row[item.prop] || '[]').length === 0">暂无图片</span>
<el-image v-else
v-for="(urlStr, index) in JSON.parse(scope.row[item.prop] || '[]')"
:key="index"
:initial-index="index"
:preview-src-list="JSON.parse(scope.row[item.prop] || '[]')"
preview-teleported
:src="urlStr"
alt="图片"
class="receipt-photo-item"
fit="cover"
style="width: 80px; height: 50px; " />
</div>
</template>
<template v-else-if="item.prop === 'logisticsTrack'">
<el-button type="primary"
@click="handleLogisticsTrack(scope.row)"
text>
查看物流轨迹
</el-button>
</template>
<template v-else-if="item.prop === 'receiptPhotoCompleteFlag'">
<el-select v-model="scope.row[item.prop]"
placeholder="请选择"
style="width: 100%"
@change="handleReceiptPhotoChangeStatus(scope.row)">
<el-option v-for="item in receiptPhotoCompleteFlagOptions"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
</template>
<template v-else-if="item.prop === 'sentStatus'">
<el-select v-model="scope.row[item.prop]"
placeholder="请选择"
filterable
style="width: 100%"
@change="handleSentStatusChange(scope.row)">
<el-option v-for="item in sentStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value" />
</el-select>
</template>
<template v-else>
<!-- 其他字段显示原始值 -->
{{ formatter(scope.row, scope.column, scope.row[item.prop]) }}
</template>
</template>
</el-table-column>
<!-- <el-table-column label="操作"
width="200"
fixed="right">
<template #default="scope">
<el-button type="danger"
@click="deleteView(scope.row)"
text>
删除
</el-button>
</template>
</el-table-column> -->
</el-table>
<!-- 分页 -->
<pagination :total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getLogisticsReceiptList" />
</div>
</div>
</template>
<script setup>
import { getLogisticsReceiptListAPI, setLogisticsReceiptStatusAPI } from '@/api'
import { parseTime, isExternal } from '@/utils'
const { proxy } = getCurrentInstance()
const { supply_logistics_shipping_order_type: typeDict } = proxy.useDict("supply_logistics_shipping_order_type")
/******************** 发货单列表 ********************/
const queryParams = reactive({
pageNum: 1,
pageSize: 10
})
const showPhoto = ref(false)
const total = ref(0)
const tableList = ref([])
// 物流轨迹链接:对应编码和地址列表
const logisticsTrack = ref([
{
code: [134, 109],
url: '#/logistics?sentNo=', // 拼接 AHSD 安徽单据编号跳转项目路由页面查看
dataKey: 'ahSentNo'
},
{
code: [132],
url: 'https://gps.rrswl.com/GPSTrackWeb/sqmmap.jsp?orderno=', // 拼接物流单号(DD 单号)
dataKey: 'expressNo'
},
{
code: [104],
url: 'https://cloud.region2.qince.com/openplat/app/dingzhi/wangxiaolu/delivery_url/redirect.do?sentNo=', // DD 单号
dataKey: 'ddNo'
}
])
const columns = ref([
{
label: '发货单 ID',
prop: 'sendId',
width: 100,
fixed: 'left'
},
{
label: 'DD 单号',
prop: 'ddNo',
width: 170,
fixed: 'left'
},
{
label: '安徽单据编号',
prop: 'ahSentNo',
width: 180,
},
{
label: '北京单据编号',
prop: 'bjSentNo',
width: 180,
},
{
label: '快递单号',
prop: 'expressNo',
width: 150
},
{
label: '版本号',
prop: 'bjSentVersion',
width: 80
},
{
label: '单据类型',
prop: 'type', // X06: 销售出库单,N02:杂发单
width: 100
},
{
label: '过账日期',
prop: 'postDate',
width: 180
},
{
label: '运输公司编码',
prop: 'transport',
width: 120
},
{
label: '运输公司',
prop: 'transportName',
width: 100
},
{
label: '签收时间',
prop: 'operateEndDateTime',
width: 180
},
{
label: '回单状态',
prop: 'receiptFlag', // 有/无/回单异常
width: 100
},
{
label: '回单照片',
prop: 'receiptPhoto',
width: 200,
className: 'col-receipt-photo',
// 根据图片数量动态计算宽度,确保图片能两列显示
// width: computed(() => {
// const maxPhotos = Math.max(...tableList.value.map(row => {
// try {
// const photos = JSON.parse(row.receiptPhoto || '[]')
// return photos.length
// } catch {
// return 0
// }
// }))
// console.log(maxPhotos, 'maxphotos')
// // 计算需要的列数,每列最多2张图片
// const columns = Math.ceil(maxPhotos / 2)
// if (columns === 0) return 200
// // 每列宽度:80px + 5px gap 间距 + 外层容器左右 padding 共 30px
// return Math.max(columns * 80 + 5 + 30)
// })
},
{
label: '创建时间',
prop: 'createTime',
width: 180
},
{
label: '更新时间',
prop: 'updateTime',
width: 180
},
{
label: '物流轨迹',
prop: 'logisticsTrack',
width: 140,
fixed: 'right'
},
{
label: '回单照片是否完整',
prop: 'receiptPhotoCompleteFlag', // 完整/不完整
width: 150,
fixed: 'right'
},
{
label: '物流状态',
prop: 'sentStatus',
width: 180,
fixed: 'right'
}
])
// 回单图片是否完整选项组
const receiptPhotoCompleteFlagOptions = ref([
{
value: '完整',
label: '完整'
},
{
value: '不完整',
label: '不完整'
}
])
// 物流状态选项组
const sentStatusOptions = ref([
{
value: '整单签收',
label: '整单签收'
},
{
value: '整单拒收',
label: '整单拒收'
},
{
value: '部分退回在途',
label: '部分退回在途'
},
{
value: '部分退回已完结',
label: '部分退回已完结'
},
{
value: '整单退回在途',
label: '整单退回在途'
},
{
value: '整单退回完结',
label: '整单退回完结'
},
{
value: '发货在途',
label: '发货在途'
},
{
value: '部分滞留',
label: '部分滞留'
},
{
value: '整单滞留',
label: '整单滞留'
}
])
// 获取发货单列表
const getLogisticsReceiptList = async () => {
const { data: { rows, total: totalNum } } = await getLogisticsReceiptListAPI(queryParams)
tableList.value = rows
total.value = totalNum
}
getLogisticsReceiptList()
// 查看物流轨迹
const handleLogisticsTrack = (row) => {
const obj = logisticsTrack.value.find(item => item.code.includes(row.transport * 1))
console.log(obj)
if (isExternal(obj?.url)) {
window.open(obj.url + row[obj.dataKey], '_blank')
} else {
window.open(window.location.href.split('/')[0] + obj.url + row[obj.dataKey], '_blank')
}
}
// 格式化表格列
const formatter = (row, columns, value) => {
// 判断有值再转换
if (columns.property === 'type') {
return typeDict.value.find(item => item.value === value)?.label
} else if (columns.property === 'createTime' || columns.property === 'updateTime') {
return parseTime(value, '{y}-{m}-{d} {h}:{i}:{s}')
} else {
return value
}
}
// 修改回单照片是否完整
const handleReceiptPhotoChangeStatus = async (row) => {
await setLogisticsReceiptStatusAPI({
sendId: row.sendId,
receiptPhotoCompleteFlag: row.receiptPhotoCompleteFlag
})
proxy.$modal.msgSuccess('修改成功')
getLogisticsReceiptList()
}
// 修改物流状态
const handleSentStatusChange = async (row) => {
await setLogisticsReceiptStatusAPI({
sendId: row.sendId,
sentStatus: row.sentStatus
})
proxy.$modal.msgSuccess('修改成功')
getLogisticsReceiptList()
}
</script>
<style scoped
lang="scss">
.table-container {
margin-top: 20px;
.header-container {
display: flex;
align-items: center;
}
::v-deep(.el-image) {
img {
width: 80px !important;
height: 50px !important;
}
}
}
.receipt-photo-container {
padding: 0 15px;
display: flex;
flex-wrap: wrap;
gap: 10px;
min-width: 200px;
/* justify-content: center; // 内容整体居中
align-items: flex-start; // 顶部对齐 */
justify-content: flex-start; // 改为左对齐,让每行都从左边开始
align-items: flex-start; // 顶部对齐
.receipt-photo-item {
border-radius: 4px;
border: 1px solid #e4e7ed;
transition: all 0.3s;
flex: 0 0 80px; // 固定宽度,不伸缩
&:hover {
border-color: #409eff;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
}
}
}
// 让表格列宽自适应内容
::v-deep(.el-table) {
.el-table__body-wrapper {
.el-table__body {
.el-table__row {
.cell {
white-space: nowrap;
overflow: visible;
}
}
td.el-table__cell.col-receipt-photo {
.cell {
padding-right: 0px; // 给回单照片列补充右内边距
padding-left: 0px; // 给回单照片列补充左内边距
text-align: center; // 内容居中
}
}
}
}
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论