Commit 3148d2be by linjinhong

Merge remote-tracking branch 'origin/lin-task' into dev

parents 57ead639 3c4b33a9
...@@ -21,6 +21,7 @@ declare module 'vue' { ...@@ -21,6 +21,7 @@ declare module 'vue' {
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog'] ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
......
...@@ -2,11 +2,11 @@ import { BasePaginationData, BaseRespData } from '@/types/api' ...@@ -2,11 +2,11 @@ import { BasePaginationData, BaseRespData } from '@/types/api'
import axios from './axios' import axios from './axios'
import { ExternalAuthListData } from '@/types/api/externalAuth' import { ExternalAuthListData } from '@/types/api/externalAuth'
export function getExternalAuthorisationListApi( export function getExternalAuthorisationListApi(
data: { data?: {
type: string type?: string
}, },
page: number, page?: number,
pageSize: number, pageSize?: number,
) { ) {
return axios.post<never, BasePaginationData<ExternalAuthListData>>( return axios.post<never, BasePaginationData<ExternalAuthListData>>(
'factory/baseExternalAccount/list_page', 'factory/baseExternalAccount/list_page',
...@@ -36,6 +36,12 @@ export function deleteExternalAuthorisationApi(ids: string) { ...@@ -36,6 +36,12 @@ export function deleteExternalAuthorisationApi(ids: string) {
`factory/baseExternalAccount/delete?ids=${ids}`, `factory/baseExternalAccount/delete?ids=${ids}`,
) )
} }
export function baseExternalAccountLogsApi(params: { ids: string }) {
return axios.get<never, BaseRespData<never>>(
`factory/baseExternalAccount/logs`,
{ params },
)
}
export function addExternalAuthorisationApi( export function addExternalAuthorisationApi(
url: string, url: string,
data: ExternalAuthListData, data: ExternalAuthListData,
......
...@@ -553,3 +553,13 @@ export function completeDeliveryApi(params: { ...@@ -553,3 +553,13 @@ export function completeDeliveryApi(params: {
params, params,
) )
} }
// 物流轨迹
export function get17TrackInfoApi(params: { id: string | number }) {
return axios.get(`factory/podJomallOrderUs/get17TrackInfo`, { params })
}
// 获取riin 权限
export function getAccountCodeByFactoryIdApi(params: { token: string }) {
return axios.get(`factory/baseExternalAccount/getAccountCodeByFactoryId`, {
params,
})
}
...@@ -7,13 +7,18 @@ import './styles/index.scss' ...@@ -7,13 +7,18 @@ import './styles/index.scss'
import VxeUITable from 'vxe-table' import VxeUITable from 'vxe-table'
import 'vxe-table/lib/style.css' import 'vxe-table/lib/style.css'
import { isPermissionBtn } from '@/utils/index'
// 确保在渲染用户提供的HTML内容时,不会执行任何潜在的恶意脚本,从而提高应用的安全性 // 确保在渲染用户提供的HTML内容时,不会执行任何潜在的恶意脚本,从而提高应用的安全性
import vueDomPurifyHTMLPlugin from 'vue-dompurify-html' import vueDomPurifyHTMLPlugin from 'vue-dompurify-html'
createApp(App) const app = createApp(App)
app
.use(vueDomPurifyHTMLPlugin) .use(vueDomPurifyHTMLPlugin)
.use(router) .use(router)
.use(store) .use(store)
.use(VxeUITable) .use(VxeUITable)
.mount('#app') .mount('#app')
app.config.globalProperties.$isPermissionBtn = isPermissionBtn
...@@ -256,6 +256,13 @@ const router = createRouter({ ...@@ -256,6 +256,13 @@ const router = createRouter({
}, },
component: WarehousePosition, component: WarehousePosition,
}, },
{
path: '/setting/settingIndex',
meta: {
title: '设置',
},
component: () => import('@/views/setting/settingIndex.vue'),
},
], ],
}, },
// 登录 // 登录
......
...@@ -192,6 +192,11 @@ const menu: MenuItem[] = [ ...@@ -192,6 +192,11 @@ const menu: MenuItem[] = [
}, },
], ],
}, },
{
index: '/setting/settingIndex',
id: 7,
label: '设置',
},
// { // {
// index: '', // index: '',
......
import { defineStore } from 'pinia'
const usePermissionBtnStore = defineStore('permissionBtn', {
state: () => ({
permissionBtns: [] as string[], // 权限按钮数组
}),
actions: {
setBtn(state: string[]) {
this.permissionBtns = state
},
},
})
export default usePermissionBtnStore
...@@ -30,8 +30,15 @@ const useUserStore = defineStore('user', { ...@@ -30,8 +30,15 @@ const useUserStore = defineStore('user', {
async login(data: LoginReq) { async login(data: LoginReq) {
try { try {
const resp = await loginApi(data) const resp = await loginApi(data)
console.log(33, resp)
this.setUser(resp.data.sysUser) this.setUser(resp.data.sysUser)
setToken(resp.data.token) setToken(resp.data.token)
localStorage.setItem(
'baseExternalAccountTypes',
JSON.stringify(resp.data.sysUser.baseExternalAccountTypes),
)
router.push({ path: '/dashboard' }) router.push({ path: '/dashboard' })
} catch (error) { } catch (error) {
// showError(error) // showError(error)
......
...@@ -24,6 +24,7 @@ export interface SysUser { ...@@ -24,6 +24,7 @@ export interface SysUser {
factoryCode: string factoryCode: string
status: number status: number
factory: Factory factory: Factory
baseExternalAccountTypes?: []
} }
export interface Factory { export interface Factory {
......
...@@ -16,4 +16,5 @@ export interface ExternalAuthListData { ...@@ -16,4 +16,5 @@ export interface ExternalAuthListData {
token?: string token?: string
refreshToken?: string refreshToken?: string
refreshTokenFailureTime?: string refreshTokenFailureTime?: string
enable?: boolean
} }
import { get } from 'lodash-es' import { get } from 'lodash-es'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { DateTime } from 'luxon' import { DateTime } from 'luxon'
import usePermissionBtnStore from '@/store/permission'
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
export function val<T>(data: T, key: string | ((data: T) => any)) { export function val<T>(data: T, key: string | ((data: T) => any)) {
if (typeof key === 'function') return key(data) if (typeof key === 'function') return key(data)
...@@ -40,3 +42,10 @@ export function convertToChinaTime( ...@@ -40,3 +42,10 @@ export function convertToChinaTime(
const chinaTime = inputTime.setZone(targetZone) const chinaTime = inputTime.setZone(targetZone)
return chinaTime.toFormat('yyyy-MM-dd HH:mm:ss') return chinaTime.toFormat('yyyy-MM-dd HH:mm:ss')
} }
export function isPermissionBtn(key: string) {
const permissionBtns = usePermissionBtnStore().permissionBtns
if (!permissionBtns) return false
return permissionBtns.includes(key)
}
...@@ -381,7 +381,9 @@ ...@@ -381,7 +381,9 @@
</ElButton> </ElButton>
</span> </span>
</ElFormItem> </ElFormItem>
<ElFormItem v-if="status === 'TO_BE_CONFIRMED'"> <ElFormItem
v-if="status === 'TO_BE_CONFIRMED' && isPermissionBtn('RIIN')"
>
<span class="item"> <span class="item">
<ElButton type="success" @click="confirmProductToRiin"> <ElButton type="success" @click="confirmProductToRiin">
转至锐印生产 转至锐印生产
...@@ -519,6 +521,7 @@ ...@@ -519,6 +521,7 @@
<ElButton type="warning" @click="arrangeFinish">排单完成</ElButton> <ElButton type="warning" @click="arrangeFinish">排单完成</ElButton>
</span> </span>
</ElFormItem> </ElFormItem>
<ElFormItem <ElFormItem
v-if="status !== 'BATCH_DOWNLOAD' && status !== 'WAIT_SHIPMENT'" v-if="status !== 'BATCH_DOWNLOAD' && status !== 'WAIT_SHIPMENT'"
> >
...@@ -1530,6 +1533,17 @@ ...@@ -1530,6 +1533,17 @@
刷新地址 刷新地址
</ElButton> </ElButton>
</span> </span>
<span
v-if="
(status === 'IN_TRANSIT' || status === 'COMPLETE') &&
isPermissionBtn('TRACK')
"
class="operate-item"
>
<ElButton link type="primary" @click="logTrajectory(row)"
>物流轨迹</ElButton
>
</span>
</div> </div>
</template> </template>
</TableView> </TableView>
...@@ -2283,6 +2297,21 @@ ...@@ -2283,6 +2297,21 @@
<el-dialog v-model="dialogVisible" width="35%"> <el-dialog v-model="dialogVisible" width="35%">
<img :src="dialogImageUrl" alt="商品预览图片" /> <img :src="dialogImageUrl" alt="商品预览图片" />
</el-dialog> </el-dialog>
<el-dialog title="物流轨迹" v-model="timeLineVisible" width="1000px">
<el-timeline>
<el-timeline-item
v-for="(item, index) in timeLine"
:key="index"
:timestamp="item.time_utc"
placement="top"
:type="index == 0 ? 'primary' : ''"
>
<el-card>
{{ item.description }}
</el-card>
</el-timeline-item>
</el-timeline>
</el-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { getUserMarkList } from '@/api/common' import { getUserMarkList } from '@/api/common'
...@@ -2350,6 +2379,8 @@ import { ...@@ -2350,6 +2379,8 @@ import {
rejectToApi, rejectToApi,
statusPushApi, statusPushApi,
completeDeliveryApi, completeDeliveryApi,
get17TrackInfoApi,
getAccountCodeByFactoryIdApi,
} from '@/api/podUsOrder' } from '@/api/podUsOrder'
import { BaseRespData } from '@/types/api' import { BaseRespData } from '@/types/api'
...@@ -2390,6 +2421,9 @@ import RightClickMenu from '@/components/RightClickMenu.vue' ...@@ -2390,6 +2421,9 @@ import RightClickMenu from '@/components/RightClickMenu.vue'
import ResultInfo from './components/ResultInfo.vue' import ResultInfo from './components/ResultInfo.vue'
import { isArray, isString } from '@/utils/validate' import { isArray, isString } from '@/utils/validate'
import platformJson from '../../../json/platform.json' import platformJson from '../../../json/platform.json'
import { getToken } from '@/api/axios'
import usePermissionBtnStore from '@/store/permission'
const permissionBtns = usePermissionBtnStore()
import { import {
useRouter, useRouter,
type NavigationGuardNext, type NavigationGuardNext,
...@@ -3857,6 +3891,24 @@ const arrangeFinish = async () => { ...@@ -3857,6 +3891,24 @@ const arrangeFinish = async () => {
loading.close() loading.close()
} }
} }
interface timeLineType {
time_iso?: string
time_utc?: string
description?: string
}
const timeLineVisible = ref(false)
const timeLine = ref<timeLineType[]>([])
const logTrajectory = async (row: { id: string }) => {
const { data } = await get17TrackInfoApi({ id: row.id })
const res = data.accepted[0]?.track_info?.tracking
timeLine.value = res?.providers[0]?.events
// if (data.rejected?.length) {
// console.log(data.rejected[0].error.message)
// throw Error(data.rejected[0].error.message)
// }
timeLineVisible.value = true
}
const logList = ref<LogListData[]>([]) const logList = ref<LogListData[]>([])
const logVisible = ref(false) const logVisible = ref(false)
const operationLog = async (id: number, e: MouseEvent | null) => { const operationLog = async (id: number, e: MouseEvent | null) => {
...@@ -4977,6 +5029,17 @@ function changeChinaTime(zone: string) { ...@@ -4977,6 +5029,17 @@ function changeChinaTime(zone: string) {
}) })
} }
const token = getToken() as string
async function getPermission() {
const res = await getAccountCodeByFactoryIdApi({ token })
permissionBtns.setBtn(res.data)
console.log(res)
}
getPermission()
const globalProperties =
getCurrentInstance()?.appContext.config.globalProperties // 获取全局挂载
const isPermissionBtn = globalProperties?.$isPermissionBtn
useRouter().beforeEach((to, from, next) => { useRouter().beforeEach((to, from, next) => {
handleBeforeRouteLeave(to, from, next) handleBeforeRouteLeave(to, from, next)
}) })
...@@ -5323,6 +5386,11 @@ useRouter().beforeEach((to, from, next) => { ...@@ -5323,6 +5386,11 @@ useRouter().beforeEach((to, from, next) => {
} }
.el-timeline-item__wrapper { .el-timeline-item__wrapper {
padding-left: 15px; padding-left: 15px;
top: -6px; top: -4px;
}
.el-timeline
> .el-timeline-item:first-child
.el-timeline-item__timestamp.is-top {
color: #409eff;
} }
</style> </style>
<template>
<div
class="user-page flex-column card h-100 overflow-hidden"
style="position: relative"
>
<div class="card-header">
<span>系统配置</span>
</div>
<div class="cardBox">
<div v-for="(item, index) in formList" style="width: 600px" :key="index">
<el-form
v-if="item.type === 'RIIN'"
class="form"
ref="formRef"
label-width="120"
:model="item"
>
<div class="formBox">
<el-form-item label="转至RIIN生产">
<el-switch
v-model="item.enable"
class="ml-2"
style="--el-switch-on-color: #42b983"
/>
</el-form-item>
<div class="formContent" v-if="item.enable">
<el-form-item
label="账号"
prop="appKey"
:rules="[{ required: true, message: '请输入RIIN账号' }]"
>
<ElInput
ref="productionOrderRef"
v-model="item.appKey"
placeholder="请输入RIIN账号"
clearable
style="width: 100%"
/></el-form-item>
<el-form-item
label="App Secret"
prop="appSecret"
:rules="[{ required: true, message: '请输入App Secret' }]"
>
<ElInput
ref="productionOrderRef"
v-model="item.appSecret"
placeholder="请输入App Secret"
clearable
style="width: 100%"
/></el-form-item>
</div>
</div>
<ElButton
class="btn"
color="#42b983"
@click="saveConfiguration(item, index)"
>保存配置</ElButton
>
</el-form>
<el-form
v-if="item.type === 'TRACK'"
class="form"
ref="formRef"
label-width="120"
:model="item"
>
<div class="formBox">
<el-form-item label="物流轨迹跟踪">
<el-switch
v-model="item.enable"
class="ml-2"
style="--el-switch-on-color: #42b983"
/>
</el-form-item>
<div class="formContent" v-if="item.enable">
<el-form-item
label="17Track账号"
prop="appKey"
:rules="[{ required: true, message: '请输入17Track账号' }]"
>
<ElInput
ref="productionOrderRef"
v-model="item.appKey"
placeholder="请输入17Track账号"
clearable
style="width: 100%"
/></el-form-item>
<el-form-item
label="账号Token"
prop="token"
:rules="[{ required: true, message: '请输入账号Token' }]"
>
<ElInput
ref="productionOrderRef"
v-model="item.token"
placeholder="请输入账号Token"
clearable
style="width: 100%"
/></el-form-item>
</div>
</div>
<ElButton
class="btn"
color="#42b983"
@click="saveConfiguration(item, index)"
>保存配置</ElButton
>
</el-form>
</div>
</div>
<div class="logBox">
<div>操作日志</div>
<LogList :log-list="logList" style="font-size: 14px; height: 100%" />
</div>
</div>
</template>
<script setup lang="ts">
import {
addExternalAuthorisationApi,
getExternalAuthorisationListApi,
baseExternalAccountLogsApi,
} from '@/api/externalAuth'
import { ExternalAuthListData } from '@/types/api/externalAuth'
interface formType {
id?: number
enable?: boolean
appKey?: string
appSecret?: string
type?: string
}
const formRef = ref()
const logList = ref([])
async function saveConfiguration(item: formType, index: number) {
let loading
try {
await formRef.value[index]?.validate()
const params = { ...item }
const url = !params.id
? 'factory/baseExternalAccount/add'
: 'factory/baseExternalAccount/update'
loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const res = await addExternalAuthorisationApi(url, params)
console.log(res)
// ElMessage.success('保存配置成功')
await ElMessageBox.confirm('保存配置成功!!需重新登录才能生效', '提示', {
confirmButtonText: '确定',
showCancelButton: false,
type: 'success',
})
await getDetail()
handleClick()
} catch (error) {
console.log(error)
} finally {
loading?.close()
}
}
const formList = ref<ExternalAuthListData[]>([])
async function getDetail() {
let loading
try {
loading = ElLoading.service({
fullscreen: true,
text: '操作中...',
background: 'rgba(0, 0, 0, 0.3)',
})
const res = await getExternalAuthorisationListApi({}, 1, 100)
const records = res.data.records || []
const newArr = records.filter((el) => el.type)
const typeSet = new Set(newArr.map((el) => el.type))
const hasRIIN = typeSet.has('RIIN')
const hasTRACK = typeSet.has('TRACK')
if (newArr.length === 0) {
formList.value = [{ type: 'RIIN' }, { type: 'TRACK' }]
} else {
const result = [...newArr]
if (!hasRIIN) result.push({ type: 'RIIN' })
if (!hasTRACK) result.push({ type: 'TRACK' })
formList.value = result
}
console.log('Form list:', formList.value)
} catch (error) {
console.error('Failed to get external authorizations:', error)
} finally {
loading?.close()
}
}
async function handleClick() {
try {
let ids = ''
const idList = formList.value.map((el) => el.id).filter((el) => el)
console.log(222, idList)
if (idList.length) {
ids = idList.join(',')
}
console.log(205, ids)
const res = await baseExternalAccountLogsApi({
ids,
})
logList.value = res.data
console.log(res)
} catch (error) {
console.log(error)
}
}
onMounted(async () => {
await getDetail()
handleClick()
})
</script>
<style lang="scss" scoped>
.card-header {
margin-left: 200px;
font-size: 30px;
margin-bottom: 20px;
}
:deep() {
.demo-tabs {
height: calc(100% - 60px);
}
.cardBox {
flex: 3;
overflow-y: scroll;
height: 100%;
.el-card__footer {
border: none !important;
}
.formBox {
width: 100%;
margin-bottom: 15px;
padding: 20px;
border: 1px solid #ebebeb;
border-radius: 8px;
&:last-child {
margin-bottom: 0;
}
.formContent {
padding: 20px;
background-color: #f9f9f9;
border-radius: 5px;
.el-form-item:last-child {
margin-bottom: 0 !important;
}
}
}
.btn {
color: #fff;
}
}
.logBox {
border-top: 1px solid #ebebeb;
padding-top: 10px;
height: 150px;
}
.form {
margin-bottom: 15px;
}
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment