Commit 225f7171 authored by 何远江's avatar 何远江

添加变量文件上传,变量标记,变量模版

parent 2c613345
import axios from "@/utils/http";
const formHeader = {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
}
/**获取变量文件 */
export const getVarFilePage = (params: any) => {
return axios.get('/api/varFile/page', {
params,
headers: formHeader
})
}
export const getOrderFileById = (id: string) => {
return axios.get('/api/varFile/getById', {
params: { id },
headers: formHeader
})
}
/**
* 解析的变量结果
* @param data
* @returns
*/
export const apiVarTemplatePage = (data: any) => {
return axios.get("/api/varTemplateDetail/page", {
params: data,
});
};
/**
* 设置变量字段
* @param data
* @returns
*/
export const apiVarTemplateSaveConf = (data: any) => {
return axios.post("/api/varTemplateDetail/saveConf", data);
};
/**
* 根据标量模板文件ID获取未转换的变量
* @param varTemplateDetailId
* @returns
*/
export const apiVarTemplateGetVars = (varTemplateDetailId: any) => {
return axios.get("/api/varTemplateDetail/getVars", {
params: { varTemplateDetailId },
});
};
/**
* 根据标量模板文件ID获取转换后变量
* @param varTemplateDetailId
* @returns
*/
export const apiVarTemplateGetNewVars = (varTemplateDetailId: any) => {
return axios.get("/api/varTemplateDetail/getNewVars", {
params: { varTemplateDetailId },
});
};
/**
* 模板变量ID获取字段配置
* @param varTemplateDetailId
* @returns
*/
export const apiVarTemplateGetConf = (varTemplateDetailId: any) => {
return axios.get("/api/varTemplateDetail/getConfByVarTemplateDetailId", {
params: { varTemplateDetailId },
});
};
/**
* 转换变量
* @param varTemplateDetailId
* @returns
*/
export const apiVarTemplateConvert = (varTemplateDetailId: any) => {
return axios.get("/api/varTemplateDetail/convert", {
params: { varTemplateDetailId },
});
};
/**
* 订单项次列表
* @param params
* @returns
*/
export const apiOrderVarPage = (params: any) => {
return axios.get("/api/orderVar/page", {
params,
});
};
/**
* 上传变量文件确认,多文件合并
* @param data
* @returns
*/
export const apiOrderVarSaveUpload = (data: any) => {
return axios.post("/api/orderVar/saveUpload", data);
};
/**
* 执行变量文件解析
* @param orderItemId
* @returns
*/
export const apiOrderVarRun = (orderItemId: any) => {
return axios.get("/api/orderVar/run", {
params: { orderItemId }
});
};
/**
* 根据标量模板文件ID获取未转换的变量
* @param orderItemId
* @returns
*/
export const apiOrderVarGetVars = (orderItemId: any) => {
return axios.get("/api/orderVar/getVars", {
params: { orderItemId }
});
};
/**
* 根据标量模板文件ID获取转换后变量
* @param orderItemId
* @returns
*/
export const apiOrderVarGetNewVars = (orderItemId: any) => {
return axios.get("/api/orderVar/getNewVars", {
params: { orderItemId }
});
};
import axios from '@/utils/http'
const formHeader = {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
}
/**
* 上传文件确认,多文件合并
* @param {Object} data
* @returns
*/
export const apiSaveUpload = (data: any) => {
return axios.post('/api/varFile/saveUpload', data)
}
export const addExcelArea = (data: any) => {
return axios.post('/api/varFile/addVarArea', data)
}
export const editExcelArea = (data: any) => {
return axios.post('/api/varFile/editVarArea', data)
}
export const getExcelAreaByFileId = (orderFileId: string) => {
return axios.get('/api/varFile/getVarAreaByFileID', {
params: { orderFileId },
headers: formHeader
})
}
export const removeExcelArea = (varAreaId: string) => {
return axios.get('/api/varFile/removeVarArea', {
params: { varAreaId },
headers: formHeader
})
}
export const getExcelConnectByFileId = (orderFileId: string) => {
return axios.get('/api/varFile/getVarAreaConnectByFileID', {
params: { orderFileId },
headers: formHeader
})
}
export const removeExcelAreaConnect = (varAreaConnectId: string) => {
return axios.get('/api/varFile/removeVarAreaConnect', {
params: { varAreaConnectId },
headers: formHeader
})
}
export const addExcelAreaConnect = (data: any) => {
return axios.post('/api/varFile/addVarAreaConnect', data)
}
export const excelMarkRun = (varFileId: string) => {
return axios.get('/api/varFile/runTemplate', {
params: { varFileId },
headers: formHeader
})
}
......@@ -12,21 +12,6 @@ const baseRoutes = [
]
export const routes = [
// {
// path: '/home',
// component: Layout,
// hiddenChild: true,
// meta: {
// title: '首页'
// },
// children: [
// {
// path: '',
// name: 'Home',
// component: () => import('@/views/home/HomeView.vue')
// }
// ]
// },
{
path: '/order',
name: 'Order',
......@@ -95,6 +80,40 @@ export const routes = [
}
]
},
{
path: '/variables',
name: 'Variables',
component: Layout,
meta: {
title: '变量管理'
},
children: [
{
path: '/variables/file',
name: 'VariablesFile',
component: () => import('@/views/var/file/fileList.vue'),
meta: {
title: '变量文件'
}
},
{
path: '/variables/list',
name: 'VariablesList',
component: () => import('@/views/var/variables/Variables.vue'),
meta: {
title: '订单变量'
}
},
{
path: '/variables/change',
name: 'VariablesChange',
component: () => import('@/views/var/varChange/VarChange.vue'),
meta: {
title: '变量转换'
}
},
]
},
{
path: '/email',
name: 'Email',
......@@ -114,40 +133,6 @@ export const routes = [
}
]
},
// {
// path: '/configure',
// name: 'Configure',
// component: Layout,
// meta: {
// title: '配置管理'
// },
// children: [
// // {
// // path: '/configure/color',
// // name: 'ConfigureColor',
// // component: () => import('@/views/configure/colors/ConfigureColor.vue'),
// // meta: {
// // title: '颜色管理'
// // }
// // },
// {
// path: '/configure/factory',
// name: 'ConfigureFactory',
// component: () => import('@/views/configure/factory/ConfigureFactory.vue'),
// meta: {
// title: '工厂管理'
// }
// },
// {
// path: '/configure/brand',
// name: 'ConfigureBrand',
// component: () => import('@/views/configure/brand/ConfigureBrand.vue'),
// meta: {
// title: '品牌管理'
// }
// }
// ]
// },
{
path: '/product',
name: 'Product',
......@@ -192,6 +177,15 @@ export const routes = [
},
component: () => import('@/views/comment-excel/CommentExcel.vue')
},
{
path: '/var-excel',
name: 'VarExcel',
hidden: true,
meta: {
title: '变量文件标注'
},
component: () => import('@/views/var/varExcel/CommentExcel.vue')
},
{
path: '/comment-upload',
name: 'CommentUpload',
......@@ -200,6 +194,14 @@ export const routes = [
},
component: () => import('@/views/comment-excel/CommentUpload.vue')
},
{
path: '/var-upload',
name: 'VarUpload',
meta: {
title: '变量上传'
},
component: () => import('@/views/var/varExcel/CommentUpload.vue')
},
{
path: '/preview-excel',
name: 'PreviewExcel',
......
......@@ -151,3 +151,59 @@ export const useExcelChangeStore = defineStore('excelChangeStore', {
}
}
})
export const useVariableExcelChangeStore = defineStore('variableExcelChangeStore', {
state: (): ExcelChangeStore => ({
allMapConfigs: {}, // 缓存当前这条数据的所有映射关系
scriptList: [], // 脚本
orderFieldList: [], // 订单字段
usedFieldList: [] // 当前编辑column使用过的映射字段
}),
getters: {
getAllMapConfigs(): Recordable {
return this.allMapConfigs
},
getScriptList(): any {
return this.scriptList
},
getEffectConfigs(): any[] {
// 获取已经使用的config,用于禁用已经选择过的映射字段
const currenttitle = this.usedFieldList[0]?.title || ''
const res: any = [...this.usedFieldList]
for (const key in this.allMapConfigs) {
if (key != currenttitle) {
if (this.allMapConfigs[key].filedConfs.length) {
res.push(...this.allMapConfigs[key].filedConfs.filter((item) => item.variable))
}
}
}
return res.map((item) => item.mapField)
},
getAllFields(): any {
return this.orderFieldList.map((item) => {
this.getEffectConfigs.includes(item.filedName)
? (item.disabled = true)
: (item.disabled = false)
return item
})
}
},
actions: {
setAllMapConfigs(config: any) {
this.allMapConfigs = config
},
setSingleFieldMap(config: any) {
this.allMapConfigs[config.title] = config
},
setScriptList(list: any) {
this.scriptList = list
},
setOrderFieldList(list: any) {
this.orderFieldList = list
},
setUsedFieldList(list: any) {
this.usedFieldList = list
}
}
})
\ No newline at end of file
......@@ -274,7 +274,7 @@ export function filterRunData(data: any, config: boolean = false) {
Reflect.set(rw, itm.title, itm.value)
titles.add(itm.title)
if (!Reflect.has(configs, itm.title) && config) {
Reflect.set(configs, itm.title, temConf)
configs[itm.title] = {...structuredClone(temConf), title: itm.title, }
}
})
// 是否有附加信息
......@@ -304,6 +304,42 @@ export function filterRunData(data: any, config: boolean = false) {
}
}
/**
* 解析后数据,处理表头和表格数据
* @param data
*/
export function filterRunData2(data: any, config: boolean = false) {
const res: Recordable[] = []
const titles: Set<string> = new Set()
// 映射字段配置生成
const configs: Recordable = {}
const temConf = {
excelOrderFiledConfId: '',
title: '',
filedConfs: [],
templateFileId: ''
}
data.forEach((row: any) => {
const rw: Recordable = {}
row.order.forEach((itm: any) => {
Reflect.set(rw, itm.title, itm.value)
titles.add(itm.title)
if (!Reflect.has(configs, itm.title) && config) {
configs[itm.title] = {...structuredClone(temConf), title: itm.title, }
}
})
res.push(rw)
})
return {
res,
titles: [...titles],
configs
}
}
/**比较两个单元格是否是同一个 */
export function compareSameCell(c1, c2) {
return c1.sheet == c2.sheet && c1.row == c2.row && c1.colum == c2.colum
......
<template>
<div class="w-full h-full bg-white p-4">
<p class="font-bold text-lg leading-10 border-b-2">订单文件管理</p>
<el-form class="pt-4" :inline="true" :model="formState">
<el-form-item label="原始文件地址">
<el-input v-model="formState.filePath" placeholder="" clearable />
</el-form-item>
<el-form-item label="标注文件地址">
<el-input v-model="formState.mergeFilePath" placeholder="" clearable />
</el-form-item>
<el-form-item>
<el-button type="default" @click="onReset">重置</el-button>
<el-button type="primary" @click="onQuery">查询</el-button>
</el-form-item>
</el-form>
<div class="">
<vxe-table
ref="xTable"
size="small"
min-height="460"
border
:loading="loading"
:data="tableData"
>
<vxe-column type="checkbox" width="50"></vxe-column>
<vxe-column field="customerId_dictText" title="客户名称" width="120"></vxe-column>
<vxe-column title="原始文件地址">
<template #default="{ row }">
<el-link
v-for="item in row.filePath.split(';')"
:key="item"
target="_blank"
:href="'/preview-excel?filePath=' + item"
>{{ item }}</el-link
>
</template>
</vxe-column>
<vxe-column title="标注文件地址">
<template #default="{ row }">
<el-link target="_blank" :href="'/preview-excel?fileId=' + row.orderFileId">{{
row.mergeFilePath
}}</el-link>
</template>
</vxe-column>
<vxe-column field="createTime" title="创建时间" width="180"></vxe-column>
<vxe-column field="action" title="操作" width="80">
<template #default="{ row }">
<el-link
type="primary"
style="font-size: 12px"
:href="'/comment-excel?fileId=' + row.varFileId"
target="_blank"
>查看</el-link
>
</template>
</vxe-column>
</vxe-table>
<vxe-pager
size="small"
background
v-model:current-page="formState.currentPage"
v-model:page-size="formState.pageSize"
:total="formState.total"
@page-change="onQuery"
:layouts="['PrevPage', 'JumpNumber', 'NextPage', 'Sizes', 'FullJump', 'Total']"
>
</vxe-pager>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref } from 'vue'
import { getVarFilePage } from '@/api/var'
import { ElMessage } from 'element-plus'
import type { VxeTableInstance } from 'vxe-table'
import { useRouter } from 'vue-router'
import { queryParamsFilter } from '@/utils/query'
const router = useRouter()
const loading = ref(false)
const formState = reactive({
filePath: '',
mergeFilePath: '',
currentPage: 1,
pageSize: 10,
total: 0,
// column: 'createTime',
// order: 'desc'
})
const xTable = ref<VxeTableInstance>()
const tableData = ref([])
const onReset = () => {
Object.assign(formState, {
filePath: '',
mergeFilePath: ''
})
}
const onQuery = async () => {
loading.value = true
try {
const { data } = await getVarFilePage(queryParamsFilter(formState))
tableData.value = data.result.records
formState.total = +data.result.total
} catch {}
loading.value = false
}
onMounted(() => {
onQuery()
})
</script>
<style lang="scss" scoped></style>
<template>
<div class="w-full h-full bg-white p-4">
<p class="font-bold text-lg leading-10 border-b-2">模版文件管理</p>
<el-form class="pt-4" :inline="true" :model="formState">
<el-form-item label="原始文件地址">
<el-input v-model="formState.filePath" placeholder="" clearable />
</el-form-item>
<el-form-item label="标注文件地址">
<el-input v-model="formState.mergeFilePath" placeholder="" clearable />
</el-form-item>
<el-form-item>
<el-button type="default" @click="onReset">重置</el-button>
<el-button type="primary" @click="onQuery">查询</el-button>
</el-form-item>
</el-form>
<div class="">
<vxe-toolbar>
<template #buttons>
<el-button type="danger" @click="removeRows">删除</el-button>
</template>
</vxe-toolbar>
<vxe-table
ref="xTable"
size="small"
min-height="460"
border
:loading="loading"
:data="tableData"
>
<vxe-column type="checkbox" width="50"></vxe-column>
<vxe-column field="customerId_dictText" title="客户名称" width="120"></vxe-column>
<vxe-column title="原始文件地址">
<template #default="{ row }">
<el-link
v-for="item in row.filePath.split(';')"
:key="item"
target="_blank"
:href="'/preview-excel?filePath=' + item"
>{{ item }}</el-link
>
</template>
</vxe-column>
<vxe-column title="标注文件地址">
<template #default="{ row }">
<el-link target="_blank" :href="'/preview-excel?fileId=' + row.orderFileId">{{
row.mergeFilePath
}}</el-link>
</template>
</vxe-column>
<vxe-column field="createTime" title="创建时间" width="180"></vxe-column>
<vxe-column field="action" title="操作" width="80">
<template #default="{ row }">
<el-link
type="primary"
style="font-size: 12px"
:href="'/comment-excel?fileId=' + row.orderFileId"
target="_blank"
>查看</el-link
>
</template>
</vxe-column>
</vxe-table>
<vxe-pager
size="small"
background
v-model:current-page="formState.currentPage"
v-model:page-size="formState.pageSize"
:total="formState.total"
@page-change="onQuery"
:layouts="['PrevPage', 'JumpNumber', 'NextPage', 'Sizes', 'FullJump', 'Total']"
>
</vxe-pager>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, reactive, ref } from 'vue'
import { getPageMarkFile, deleteOrderFiles } from '@/api/order'
import { ElMessage } from 'element-plus'
import type { VxeTableInstance } from 'vxe-table'
import { useRouter } from 'vue-router'
import { queryParamsFilter } from '@/utils/query'
const router = useRouter()
const loading = ref(false)
const formState = reactive({
filePath: '',
mergeFilePath: '',
currentPage: 1,
pageSize: 10,
total: 0,
column: 'createTime',
order: 'desc'
})
const xTable = ref<VxeTableInstance>()
const tableData = ref([])
const removeRows = async () => {
const list = xTable.value?.getCheckboxRecords()
if (list?.length) {
const ids = list.map((v) => v.orderFileId).join(',')
await deleteOrderFiles(ids)
ElMessage.success('删除成功')
onQuery()
}
}
const onReset = () => {
Object.assign(formState, {
filePath: '',
mergeFilePath: ''
})
}
const onQuery = async () => {
loading.value = true
try {
const { data } = await getPageMarkFile(queryParamsFilter(formState))
tableData.value = data.result.records
formState.total = +data.result.total
} catch {}
loading.value = false
}
onMounted(() => {
onQuery()
})
</script>
<style lang="scss" scoped></style>
This diff is collapsed.
<template>
<el-scrollbar max-height="350px">
<el-form size="small" label-width="60px">
<template v-for="(item, index) in configList" :key="item.time">
<ConfigFormItem :item="item" :index="index" @remove="removeMapField" />
<el-divider v-if="index + 1 != configList.length">{{ index + 2 }}映射字段 </el-divider>
</template>
</el-form>
</el-scrollbar>
<el-row type="flex" justify="center">
<el-button size="small" type="primary" @click="emits('confirm', configList)">确认</el-button>
<el-button size="small" type="primary" @click="addFormItem">添加字段</el-button>
<el-button size="small" @click="emits('cancel')">取消</el-button>
</el-row>
</template>
<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from 'vue'
import type { Recordable } from '@/types/global'
import ConfigFormItem from './ConfigFormItem.vue'
import { cloneDeep } from 'loadsh'
import { ElMessage } from 'element-plus'
import { apiGetOrderField, apiGetScript, getVariableField } from '@/api/excel'
import { useVariableExcelChangeStore } from '@/stores/excel'
/**
* 数据结构
* {templateFileId: '', confs: [{title: '',filedConfs: [{mapField: '',orderFiled: {}, scripts: {}}], templateFileId: ''}]}
*/
const props = defineProps<{ title: string; currentRow: Recordable; currentConf: Recordable }>()
const emits = defineEmits(['cancel', 'confirm'])
const excelChangeStore = useVariableExcelChangeStore()
const configList = ref<Recordable[]>([])
// 添加映射字段表单对象
const addFormItem = () => {
configList.value.push({
time: Date.now(),
mapField: '',
orderFiled: {},
scripts: []
})
}
const removeMapField = (index: number) => {
configList.value.splice(index, 1)
}
const getScriptList = async () => {
const { data } = await apiGetScript()
excelChangeStore.setScriptList(data.result)
}
const getOrderFields = async () => {
const { data } = await apiGetOrderField()
excelChangeStore.setOrderFieldList(data.result)
}
watch(
() => props.currentConf.title,
(val) => {
configList.value = cloneDeep(props.currentConf).filedConfs.map((item, i) => {
item.time = Date.now() + i
return item
})
},
{
immediate: true
}
)
watch(
configList,
(val) => {
excelChangeStore.setUsedFieldList(val)
},
{ deep: true }
)
onMounted(() => {
getScriptList()
getOrderFields()
})
</script>
<template>
<!-- 字段映射设置 -->
<el-col>
<el-form-item label="对应字段" prop="mapField">
<!-- <el-select
v-if="!isVariable"
v-model="item.mapField"
style="width: 160px"
filterable
placeholder="请选择"
@change="mapFieldChange"
clearable
>
<el-option
v-for="item in getAllFields"
:key="item.filedName"
:label="item.fliedTitle"
:value="item.filedName"
:disabled="!!item.disabled"
/>
</el-select> -->
<el-input v-model="item.mapField" style="width: 260px" />
<!-- <el-checkbox class="ml-1" v-model="isVariable" @change="checkboxChange">是变量</el-checkbox> -->
<el-button
class="ml-1"
v-if="props.index != 0"
plain
circle
type="danger"
@click="emits('remove', props.index)"
><el-icon><CircleClose /></el-icon
></el-button>
</el-form-item>
</el-col>
<!-- 脚本设置 -->
<el-col :span="24" v-if="item.mapField">
<template v-for="(sitem, idx) in item.scripts">
<el-form-item :label="'脚本' + (idx ? idx + 1 : '')">
<el-row>
<el-col>
<el-select
style="width: 260px"
v-model="sitem.scriptName"
@change="(e) => scriptChange(sitem, e)"
clearable
>
<el-option
v-for="item in getScriptList"
:key="item.srciptName"
:value="item.srciptName"
:label="item.srciptName"
></el-option>
</el-select>
<span class="ml-1">
<el-button v-if="idx == 0" @click="addScript" type="primary" circle
><el-icon><Plus /></el-icon
></el-button>
<el-button v-if="idx != 0" @click="removeScript(idx)" type="danger" plain circle
><el-icon><Minus /></el-icon
></el-button>
</span>
</el-col>
<el-col v-if="sitem.scriptName" class="mt-1">
<el-input
type="textarea"
style="width: 270px"
rows="5"
v-model="sitem.content"
></el-input>
</el-col>
</el-row>
</el-form-item>
</template>
</el-col>
</template>
<script lang="ts" setup>
import { useVariableExcelChangeStore } from '@/stores/excel'
import { Plus, Minus, CircleClose } from '@element-plus/icons-vue'
import { storeToRefs } from 'pinia'
import { onMounted, ref, watch } from 'vue'
const props = defineProps<{ item?: any; index: number }>()
const emits = defineEmits(['remove'])
const excelChangeStore = useVariableExcelChangeStore()
const { getScriptList } = storeToRefs(excelChangeStore)
const isVariable = ref(false)
const scriptChange = (sitem, e) => {
if (e) {
sitem.content = getScriptList.value.find((item) => item.srciptName == e)?.scriptContent
} else {
sitem.content = ''
}
}
const checkboxChange = (e) => {
// 设置一个属性
props.item.isVariable = isVariable.value
props.item.mapField = ''
props.item.orderFiled = null
}
const removeScript = (index: number) => {
props.item.scripts.splice(index, 1)
}
const addScript = () => {
props.item.scripts.push({
content: '',
scriptName: ''
})
}
onMounted(() => {
console.log('onmounted')
// isVariable.value = !!props.item.orderFiled?.variable
})
watch(
() => props.item.mapField,
(val) => {
// 如果有值,添加脚本
if (val && props.item.scripts.length == 0) {
props.item.scripts.push({
content: '',
scriptName: ''
})
}
}
)
</script>
<style lang="scss" scoped></style>
<template>
<vxe-modal
v-model="showEdit"
:z-index="1006"
@hide="onHide"
title="客户选择"
width="800"
esc-closable
mask-closable
show-footer
>
<template #default>
<vxe-table ref="xTable" border :data="data" size="small" height="400">
<vxe-column v-for="column in titles" :key="item" :field="column" :title="column"></vxe-column>
</vxe-table>
</template>
<template #footer>
<el-button type="primary" @click="showEdit = false">关闭</el-button>
</template>
</vxe-modal>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted, reactive, watch, unref } from 'vue'
import { getCustomerPage } from '@/api/customer'
import type { VxeTableInstance } from 'vxe-table'
import { ElMessage } from 'element-plus'
export default defineComponent({
name: 'TemplateVariables',
props: {
visible: {
type: Boolean,
default: false
},
titles: {
type: Array,
default: () => []
},
data: {
type: Array,
default: () => []
}
},
emits: ['update:visible'],
setup(props, { emit }) {
const showEdit = ref(false)
const xTable = ref<VxeTableInstance>()
const tableData = ref([])
watch(
() => props.visible,
(val) => {
showEdit.value = val
}
)
const onHide = () => {
emit('update:visible', false)
}
return {
showEdit,
xTable,
tableData,
onHide,
}
}
})
</script>
<style lang="scss" scoped></style>
\ No newline at end of file
<template>
</template>
<script setup lang="ts">
</script>
<style lang="scss" scoped></style>
\ No newline at end of file
<template>
<ExcelOperate v-if="loading" />
<el-button class="page-back" type="primary" size="large" :icon="Back" circle @click="pageBack" />
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { getOrderFileById } from '@/api/var'
import { useCommentExcel } from '@/stores/commentExcel'
import ExcelOperate from './components/ExcelOperate/ExcelOperate.vue'
import { Back } from '@element-plus/icons-vue'
const loading = ref(false)
const route = useRoute()
const router = useRouter()
const { setFileInfo } = useCommentExcel()
// 获取文件信息及客户信息
const queryFileInfo = async () => {
const { data } = await getOrderFileById(route.query.fileId as string)
setFileInfo(data.result)
loading.value = true
}
const pageBack = () => {
router.go(-1)
}
onMounted(() => {
route.query?.fileId && queryFileInfo()
})
</script>
<style lang="scss" scoped>
.page-back {
position: fixed;
top: 0px;
right: 30px;
z-index: 1001;
}
</style>
<template>
<ChooseFile @upload="uploadSuccess" />
</template>
<script lang="ts" setup>
import { useRouter } from 'vue-router'
import ChooseFile from './components/ChooseFile/ChooseFile.vue'
const router = useRouter()
const uploadSuccess = (data) => {
router.replace({
path: '/var-excel',
query: {
fileId: data.varFileId
}
})
}
</script>
<style lang="scss" scoped></style>
<template>
<div class="container m-auto pt-10">
<el-form ref="formRef" :model="formState" label-width="100px">
<el-form-item label="客户:">
<el-input v-model="formState.customerName" disabled>
<template #append>
<el-button :icon="MoreFilled" @click="visible = true" />
</template>
</el-input>
</el-form-item>
<el-form-item label="产品:">
<el-input v-model="formState.productName" disabled>
<template #append>
<el-button :icon="MoreFilled" @click="prodVisible = true" />
</template>
</el-input>
</el-form-item>
<el-form-item label="选择文件:">
<el-upload
action=""
accept=".xlsx,.xls"
:auto-upload="false"
:show-file-list="false"
:on-change="changeUpload"
>
<el-button type="primary">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">选择你要上传的excel文件,仅支持xlsx、xls格式</div>
</template>
</el-upload>
<el-table :data="tableData" border size="small" style="width: 100%">
<el-table-column prop="filename" label="文件名称" />
<el-table-column
prop="filesize"
label="文件大小"
:formatter="(r, c, v) => v + ' B'"
width="180"
/>
<el-table-column prop="action" label="操作" width="90">
<template #default="{ $index }">
<el-button type="danger" size="small" @click="removeFile($index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
<el-button type="default" @click="goBack">返回</el-button>
</el-form-item>
</el-form>
</div>
<CustomerModal v-model:visible="visible" @confirm="confirmCustomer" />
<ProductModal v-model:visible="prodVisible" @confirm="confirmProduct" />
</template>
<script lang="ts" setup>
import axios from 'axios'
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import { useCommentExcel } from '@/stores/commentExcel'
import { MoreFilled } from '@element-plus/icons-vue'
import CustomerModal from '@/components/CustomerModal/CustomerModal.vue'
import ProductModal from '@/components/ProductModal/ProductModal.vue'
import { apiSaveUpload } from '@/api/varExcel'
import { uploadFile } from '@/api/excel'
const visible = ref(false)
const prodVisible = ref(false)
const formRef = ref()
const tableData = ref([])
const formState = reactive({
customerName: '',
customerId: '',
productName: '',
productCode: '',
})
const emit = defineEmits(['upload'])
const removeFile = (i: number) => tableData.value.splice(i, 1)
const changeUpload = (file: any) => {
const formData = new FormData()
formData.append('file', file.raw)
uploadFile(formData).then(({ data }) => {
if (data?.code === 200) {
tableData.value.push({
filename: file.name,
filesize: file.size,
url: data.message
})
} else {
return ElMessage.error('上传失败!')
}
})
}
const confirmProduct = (list: any) => {
const [item] = list
if (!item) return
formState.productCode = item.productCode
formState.productName = item.productName
}
const confirmCustomer = (list: any) => {
const [item] = list
if (!item) return
formState.customerId = item.customerId
formState.customerName = item.customerName
}
const submitForm = async () => {
await formRef.value.validate()
if (!tableData.value.length) {
return
}
const params = {
filePaths: tableData.value.map((item) => item.url),
customerId: formState.customerId,
productCode: formState.productCode
}
apiSaveUpload(params).then(({ data }) => {
// const { setFileInfo } = useCommentExcel()
// setFileInfo(data.result)
emit('upload', data.result)
})
}
const goBack = () => {
const router = useRouter()
router.go(-1)
}
</script>
<style lang="scss" scoped></style>
This diff is collapsed.
<template>
<vxe-modal
v-model="modalVisible"
title="设置产品对照"
@hide="onHide"
esc-closable
mask-closable
:show-footer="false"
:z-index="1003"
>
<el-form
ref="formRef"
size="small"
inline
label-width="80px"
:model="formState"
:rules="formRules"
>
<el-row :gutter="24">
<el-col :span="24">
<el-form-item label="产品名称" prop="productId_dictText">
<el-input v-model="formState.productId_dictText" disabled>
<template #append>
<el-button :icon="MoreFilled" @click="openModal('prod')" />
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="客户名称" prop="customerId_dictText">
<el-input v-model="formState.customerId_dictText" disabled>
<template #append>
<el-button :icon="MoreFilled" @click="openModal('cust')" />
</template>
</el-input>
</el-form-item>
</el-col>
<!-- <el-col :span="24">
<el-form-item label="产品单位" prop="customerUnit">
<el-input v-model="formState.customerUnit"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="单位" prop="unit">
<el-input v-model="formState.unit"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="换算值" prop="unitRatio">
<el-input type="number" v-model="formState.unitRatio"></el-input>
</el-form-item>
</el-col> -->
<el-col :span="24">
<el-form-item label="产品描述" prop="excelFiled">
<el-input
disabled
style="width: 250px"
type="textarea"
:rows="5"
v-model="formState.excelFiled"
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row type="flex" justify="center">
<el-button size="default" type="primary" @click="onSubmit" :loading="saveLoading"
>提交</el-button
>
<el-button size="default" @click="modalVisible = false">取消</el-button>
</el-row>
</el-form>
</vxe-modal>
<ProductModal v-model:visible="prodVisible" @confirm="(list) => confirmModal(list, 'prod')" />
<CustomerModal
v-model:visible="customerVisible"
@confirm="(list) => confirmModal(list, 'customer')"
/>
</template>
<script lang="ts" setup>
import { reactive, ref, watch } from 'vue'
import ProductModal from '@/components/ProductModal/ProductModal.vue'
import CustomerModal from '@/components/CustomerModal/CustomerModal.vue'
import { MoreFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { saveExcelProdFileConf } from '@/api/product'
import { useCommentExcel } from '@/stores/commentExcel'
const { getFileInfo } = useCommentExcel()
const props = defineProps(['visible'])
const emits = defineEmits(['confirm', 'update:visible', 'success'])
const formRef = ref()
const modalVisible = ref(false)
const prodVisible = ref(false)
const customerVisible = ref(false)
const saveLoading = ref(false)
const luckysheet = (window as any).luckysheet
const formRules = reactive({})
const formState = reactive({
customerId: '',
productId: '',
customerId_dictText: '',
productId_dictText: '',
excelFiled: '',
customerUnit: '',
unit: '',
unitRatio: ''
})
watch(
() => props.visible,
(val) => {
modalVisible.value = val
if (val) {
// 如果有客户,默认带出来
formState.customerId = getFileInfo.customerId || ''
formState.customerId_dictText = getFileInfo.customerId_dictText || ''
formState.excelFiled = getText()
}
}
)
const getText = () => {
const { luckysheet_select_save } = luckysheet.getSheet()
if (!luckysheet_select_save.length) return
const effectVal: any = []
luckysheet_select_save.forEach((area) => {
const rangeJson = luckysheet.getRangeJson(false, { column: area.column, row: area.row })
rangeJson.forEach((item) => {
const vs = Object.values(item)
effectVal.push(...vs.filter((v) => !!v))
})
})
return effectVal.join(';')
}
// 表单提交
const onSubmit = async () => {
await formRef.value.validate()
saveLoading.value = true
try {
await saveExcelProdFileConf(formState)
ElMessage.success('操作成功!')
modalVisible.value = false
emits('success')
} catch {}
saveLoading.value = false
}
const onHide = () => {
// 重置表单
Object.assign(formState, {
customerId: '',
productId: '',
customerId_dictText: '',
productId_dictText: '',
excelFiled: '',
customerUnit: '',
unit: '',
unitRatio: ''
})
emits('update:visible', false)
}
const openModal = (type: string) => {
if (type == 'prod') {
prodVisible.value = true
} else {
customerVisible.value = true
}
}
const confirmModal = (list: any, type: string) => {
const [item] = list
if (type == 'prod') {
formState.productId = item.productId
formState.productId_dictText = item.productName
} else {
formState.customerId = item.customerId
formState.customerId_dictText = item.customerName
}
}
</script>
<style lang="scss" scoped></style>
<template>
<div class="setdata-step">
<el-steps :active="activeStep" finish-status="success" simple>
<el-step title="数据区" />
<el-step title="标题区" />
<el-step title="附加信息" />
</el-steps>
<SetDataArea
v-show="activeStep == 0"
:areaTypeLen="areaTypeLen"
ref="setDataAreaRef"
@next="nextStep"
/>
<SetDataAreaTitle
ref="setDataAreaTitleRef"
v-show="activeStep == 1"
:current-area-mark="currentAreaMark"
@next="nextStep"
/>
<SetAttch
ref="setAttchRef"
v-show="activeStep == 2"
:current-area-mark="currentAreaMark"
@next="nextStep"
/>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, unref } from 'vue'
import SetDataArea from '../SetDataArea/SetDataArea.vue'
import SetDataAreaTitle from '../SetDataAreaTitle/SetDataAreaTitle.vue'
import SetAttch from '../SetAttch/SetAttch.vue'
import type { Recordable } from '@/types/global'
import { addExcelArea } from '@/api/varExcel'
import { ElLoading, ElMessage } from 'element-plus'
import { storeToRefs } from 'pinia'
import { useCommentExcel } from '@/stores/commentExcel'
const props = defineProps(['areaTypeLen'])
const commentExcelStore = useCommentExcel()
const { getFileInfo } = storeToRefs(commentExcelStore)
const emits = defineEmits(['success'])
const activeStep = ref(0)
const setAttchRef = ref()
const setDataAreaRef = ref()
const setDataAreaTitleRef = ref()
const currentAreaMark = reactive<Recordable>({})
const nextStep = async (index = 1, data: any) => {
switch (activeStep.value) {
case 0:
Object.assign(currentAreaMark, unref(data))
break
case 1:
if (data) {
Object.assign(currentAreaMark, {
titleArea: JSON.stringify(data.titleArea),
excelAreaTitle: data.excelAreaTitle
})
}
if (index == -2) {
currentAreaMark.desGroups = []
// 保存
await saveArea()
index = -1
}
break
case 2:
if (index != -1) {
if (data.desGroups.beginRow != '') {
currentAreaMark.desGroups = [data.desGroups]
} else {
currentAreaMark.desGroups = []
}
try {
// 保存
saveArea()
} catch {
return
}
}
break
default:
break
}
activeStep.value += index
}
const saveArea = async () => {
currentAreaMark.fileId = getFileInfo.value.varFileId
const loadingInstance = ElLoading.service({
fullscreen: true
})
try {
const { data } = await addExcelArea(currentAreaMark)
if (data.code == 200 && data.result != null) {
ElMessage.success('保存成功!')
// 保存成功。清空组件状态
setDataAreaRef.value.resetFormState()
setDataAreaTitleRef.value.resetExcelAreaTitleState()
setAttchRef.value.resetFormState()
emits('success', data)
} else {
return ElMessage.error(data.message || '保存失败!')
}
} catch {}
loadingInstance.close()
}
</script>
<style lang="scss">
.setdata-step {
.el-steps--simple {
padding: 8px 15px 0;
}
.el-step.is-simple {
.el-step__title {
font-size: 12px;
}
.el-step__arrow {
&::before {
transform: rotate(-45deg) translateY(-2px);
transform-origin: 0 0;
height: 8px;
}
&::after {
transform: rotate(45deg) translateY(2px);
transform-origin: 100% 100%;
height: 8px;
}
}
}
}
</style>
<template>
<div class="set-attch-table">
<el-button size="small" @click="back">上一步</el-button>
<p style="font-size: 12px">
附加区域:<el-tag>{{
getRangetxt(formState.beginRow, formState.endRow, formState.beginColum, formState.endColum)
}}</el-tag>
</p>
<vxe-table
style="margin-top: 8px"
:row-config="{ isCurrent: true }"
border
:data="groupTitles"
size="mini"
max-height="200"
:edit-config="{ trigger: 'click', mode: 'cell' }"
>
<vxe-column title="别称" field="title" :edit-render="{}">
<template #edit="{ row }">
<el-input size="small" v-model="row.title"></el-input>
</template>
</vxe-column>
<vxe-column title="单元格" field="area" width="100">
<template #default="{ row }">
{{ getRangetxt(row.row, row.row, row.colum, row.colum) }}
</template>
</vxe-column>
<vxe-column title="操作" field="action" width="90">
<template #default="{ row, $rowIndex }">
<el-link style="font-size: 12px" type="danger" @click="delGroupTitle($rowIndex)"
>删除</el-link
>
</template>
</vxe-column>
</vxe-table>
<vxe-table
style="margin-top: 8px"
:row-config="{ isCurrent: true }"
border
:data="areaTitles"
size="mini"
max-height="200"
:edit-config="{ trigger: 'click', mode: 'cell' }"
>
<vxe-column title="标题" field="title" :edit-render="{}">
<template #edit="{ row }">
<el-input v-model="row.title" size="small"></el-input>
</template>
</vxe-column>
<vxe-column title="单元格" field="cell" width="100">
<template #default="{ row }">
{{ getRangetxt(row.row, row.row, row.colum, row.colum) }}
</template>
</vxe-column>
<vxe-column title="是否拆分" field="numFlag" width="70">
<template #default="{ row }">
<el-checkbox
size="small"
true-label="Y"
false-label="N"
v-model="row.numFlag"
@change="(e) => numFlagChange(e, row)"
></el-checkbox>
</template>
</vxe-column>
<vxe-column title="特性" field="numTitle" width="90">
<template #default="{ row }">
<el-input :disabled="row.numFlag == 'N'" v-model="row.numTitle" size="small"></el-input>
</template>
</vxe-column>
<vxe-column title="操作" field="action" width="50">
<template #default="{ row, $rowIndex }">
<el-link style="font-size: 12px" type="danger" @click="delAreaTitle($rowIndex, row)"
>删除</el-link
>
</template>
</vxe-column>
</vxe-table>
<el-button-group class="mt-2">
<el-button type="primary" size="small" @click="setAttch">设置附加信息</el-button>
<el-button type="primary" size="small" @click="setNickName">设置别称</el-button>
<el-button type="primary" size="small" @click="setAttchTitle">设置标题</el-button>
<el-button type="primary" size="small" @click="setNumFlag">设置拆分</el-button>
<el-button type="success" size="small" @click="save">保存</el-button>
</el-button-group>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref, unref } from 'vue'
import { compareSameCell, getRangePosition, getRangetxt, handleRangeTitle } from '@/utils/excel'
import type { Recordable } from '@/types/global'
import { areaMarksColor } from '@/constants/excelConfig'
import { ElMessage } from 'element-plus'
const luckysheet = (window as any).luckysheet
const emits = defineEmits(['next'])
const formState = reactive<Recordable>({
beginRow: '',
beginColum: '',
endRow: '',
endColum: '',
sheetNum: ''
})
const areaTitles = ref<Recordable[]>([])
const groupTitles = ref<Recordable[]>([])
/**
* 设置附加信息
*/
const setAttch = () => {
const position = getRangePosition()
if (!position) return
if (formState.beginRow != '') {
luckysheet.menuButton.customUpdateFormat(
null,
'bg',
areaMarksColor['data'],
formState.beginRow,
formState.endRow,
formState.beginColum,
formState.endColum,
false
)
}
luckysheet.setRangeFormat('bg', areaMarksColor['attch'])
Object.assign(formState, position)
}
const numFlagChange = ([val], row: any) => {
if (val == 'Y') {
!row.numTitle && (row.numTitle = '尺码')
} else {
row.numTitle = ''
}
}
/**
* 设置附加信息标题
*/
const setAttchTitle = () => {
if (formState.beginRow == '') {
return ElMessage.error('请先设置附加信息区域!')
}
const position = getRangePosition()
if (!position) return
// 清除颜色
if (areaTitles.value.length) {
areaTitles.value.forEach((item) => {
luckysheet.menuButton.customUpdateFormat(
null,
'bg',
areaMarksColor['attch'],
item.row,
item.row,
item.colum,
item.colum,
false
)
})
}
const rangeData = luckysheet.getRangeValue()
const aTitles = handleRangeTitle(rangeData).map((item) => {
Reflect.set(item, 'numTitle', '')
Reflect.set(item, 'numFlag', 'N')
return item
})
areaTitles.value = aTitles
luckysheet.setRangeFormat('bg', areaMarksColor['attch_title'])
}
const setNumFlag = () => {
if (!areaTitles.value.length) return
const rangeData = luckysheet.getRangeValue()
const titles = handleRangeTitle(rangeData)
// 匹配到的第一个单元格下标
const idx = areaTitles.value.findIndex((item) => {
return compareSameCell(item, titles[0])
})
if (idx == -1) return
for (let i = 0; i <= titles.length - 1; i++) {
const cell = areaTitles.value[i + idx]
if (!cell) return
Reflect.set(cell, 'numFlag', 'Y')
!cell.numTitle && Reflect.set(cell, 'numTitle', '尺码')
}
}
/**
* 设置附加信息别称
* @param row
*/
const setNickName = () => {
if (formState.beginRow == '') {
return ElMessage.error('请先设置附加信息区域!')
}
const position = getRangePosition()
if (!position) return
// 清除颜色
if (groupTitles.value.length) {
groupTitles.value.forEach((item) => {
luckysheet.menuButton.customUpdateFormat(
null,
'bg',
areaMarksColor['attch'],
item.row,
item.row,
item.colum,
item.colum,
false
)
})
}
const rangeData = luckysheet.getRangeValue()
const gTitles = handleRangeTitle(rangeData, unref(formState))
groupTitles.value = gTitles
luckysheet.setRangeFormat('bg', areaMarksColor['attch_head'])
}
// 删除附加信息别称
const delGroupTitle = (index: number) => {
groupTitles.value.splice(index, 1)
}
// 删除区域标题
const delAreaTitle = (index: number) => {
areaTitles.value.splice(index, 1)
}
const save = () => {
// 如果设置了附加信息,必须要设置别称
if (formState.beginRow != '') {
if (!groupTitles.value.length) {
return ElMessage.error('请设置附加信息区域的别称!')
}
}
emits('next', -2, {
desGroups: {
...formState,
areaTitles: unref(areaTitles),
groupTitles: unref(groupTitles)
}
})
}
// 重置附加信息颜色
const resetAttchBg = () => {
if (formState.beginRow != '') {
luckysheet.menuButton.customUpdateFormat(
null,
'bg',
areaMarksColor['data'],
formState.beginRow,
formState.endRow,
formState.beginColum,
formState.endColum,
false
)
}
}
const resetFormState = () => {
Object.assign(formState, {
beginRow: '',
endRow: '',
beginColum: '',
endColum: '',
sheetNum: 0
})
groupTitles.value = []
areaTitles.value = []
}
const back = () => {
// 清空颜色
resetAttchBg()
resetFormState()
emits('next', -1)
}
defineExpose({
resetFormState
})
</script>
<style lang="scss" scoped>
.set-attch-table {
padding: 8px;
}
</style>
This diff is collapsed.
<template>
<div class="excel-title-table">
<el-button size="small" @click="nextStep(-1)">上一步</el-button>
<vxe-table
:row-config="{ isCurrent: true }"
border
:data="excelAreaTitle"
size="mini"
height="200"
:edit-config="{ trigger: 'click', mode: 'cell' }"
>
<vxe-column title="title" field="title" :edit-render="{}" width="150">
<template #edit="{ row }">
<el-input v-model="row.title" size="small"></el-input>
</template>
</vxe-column>
<vxe-column title="单元格" field="cell" width="90">
<template #default="{ row }">
{{ getRangetxt(row.row, row.row, row.colum, row.colum) }}
</template>
</vxe-column>
<vxe-column title="是否填充" width="70">
<template #default="{ row }">
<el-checkbox
size="small"
true-label="Y"
false-label="N"
v-model="row.fillFlag"
></el-checkbox>
</template>
</vxe-column>
<vxe-column title="是否拆分" field="numFlag" width="70">
<template #default="{ row }">
<el-checkbox
size="small"
true-label="Y"
false-label="N"
v-model="row.numFlag"
@change="(e) => numFlagChange(e, row)"
></el-checkbox>
</template>
</vxe-column>
<vxe-column title="特性" field="numTitle" width="90">
<template #default="{ row }">
<el-input :disabled="row.numFlag == 'N'" v-model="row.numTitle" size="small"></el-input>
</template>
</vxe-column>
<vxe-column title="操作" field="action" width="50">
<template #default="{ row, $rowIndex }">
<el-link style="font-size: 12px" type="danger" @click="delAreaTitle($rowIndex, row)"
>删除</el-link
>
</template>
</vxe-column>
</vxe-table>
<el-button-group>
<el-button size="small" type="primary" @click="setAreaTitle">标记标题</el-button>
<el-button size="small" type="primary" @click="numFlagModalVisible = true"
>设置拆分</el-button
>
<el-button size="small" type="primary" @click="setFill">设置填充</el-button>
<el-button size="small" type="primary" @click="resetAreaTitle">重置</el-button>
<el-button size="small" type="success" @click="nextStep()">下一步</el-button>
<el-button size="small" type="success" @click="save">保存</el-button>
</el-button-group>
<vxe-modal title="设置拆分" v-model="numFlagModalVisible" size="small">
<el-form size="small" :model="numFlagForm" label-width="80px">
<el-form-item label="特性名称">
<el-input v-model="numFlagForm.numTitle"></el-input>
</el-form-item>
<el-form-item label="是否唯一">
<el-checkbox false-label="N" true-label="Y" v-model="numFlagForm.only"></el-checkbox>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="setNumFlag">确定</el-button>
<el-button @click="numFlagModalVisible = false">取消</el-button>
</el-form-item>
</el-form>
</vxe-modal>
</div>
</template>
<script lang="ts" setup>
import { ref, reactive, unref } from 'vue'
import { compareSameCell, getRangetxt, handleRangeCell, handleRangeTitle } from '@/utils/excel'
import { areaMarksColor } from '@/constants/excelConfig'
import { ElMessage } from 'element-plus'
import type { Recordable } from '@/types/global'
const props = defineProps({
currentAreaMark: {
type: Object,
default: () => ({})
}
})
const luckysheet = (window as any).luckysheet
const emits = defineEmits(['next'])
const excelAreaTitle = ref<Recordable[]>([])
const titleArea = ref<Recordable[]>([])
const numFlagModalVisible = ref(false)
const numFlagForm = reactive({
numTitle: '尺码',
only: 'N'
})
/**设置拆分 */
const setNumFlag = () => {
if (!excelAreaTitle.value.length) return
const rangeData = luckysheet.getRangeValue()
const titles = handleRangeTitle(rangeData)
// 匹配到的第一个单元格下标
const idx = excelAreaTitle.value.findIndex((item) => {
return compareSameCell(item, titles[0])
})
if (idx == -1) return
for (let i = 0; i <= titles.length - 1; i++) {
const cell = excelAreaTitle.value[i + idx]
if (!cell) return
Reflect.set(cell, 'numFlag', 'Y')
Reflect.set(cell, 'only', numFlagForm.only)
!cell.numTitle && Reflect.set(cell, 'numTitle', numFlagForm.numTitle)
}
numFlagModalVisible.value = false
}
/**设置填充 */
const setFill = () => {
if (!excelAreaTitle.value.length) return
const rangeData = luckysheet.getRangeValue()
const titles = handleRangeTitle(rangeData)
// 匹配到的第一个单元格下标
const idx = excelAreaTitle.value.findIndex((item) => {
return compareSameCell(item, titles[0])
})
if (idx == -1) return
for (let i = 0; i <= titles.length - 1; i++) {
const cell = excelAreaTitle.value[i + idx]
if (!cell) return
Reflect.set(cell, 'fillFlag', 'Y')
}
}
const setAreaTitle = () => {
const sheet = luckysheet.getSheet()
// 判断是否在同一sheet
if (sheet.order != props.currentAreaMark.sheetNum) {
return ElMessage.error('请在同一sheet页中选择数据!')
}
const isPublic = props.currentAreaMark.excelAreaType == 'public_area'
const [sr, er] = sheet.luckysheet_select_save[0].row
const [sc, ec] = sheet.luckysheet_select_save[0].column
const rangeData = luckysheet.getRangeValue()
const titles = isPublic
? handleRangeCell(rangeData)
: handleRangeTitle(rangeData).map((item) => {
Reflect.set(item, 'numTitle', '')
Reflect.set(item, 'numFlag', 'N')
Reflect.set(item, 'fillFlag', 'N')
Reflect.set(item, 'only', 'N')
return item
})
titleArea.value.push({
excelAreaNicname: props.currentAreaMark.excelAreaNicname,
sr,
sc,
er,
ec
})
if (excelAreaTitle.value.length) {
const arr = [...titles, ...unref(excelAreaTitle)]
excelAreaTitle.value = uniqArrayObject(arr)
} else {
excelAreaTitle.value = titles
}
function uniqArrayObject(arr = []) {
return arr.reduce((cur, pre, index) => {
if (index == 0) {
cur.push(pre)
} else {
const isDiff = cur.every((item) => {
return (
item.column != pre.column ||
item.row != pre.row ||
item.sheet != pre.sheet ||
item.title != pre.title
)
})
isDiff && cur.push(pre)
}
return cur
}, [])
}
setAreaTitleBg('head')
}
const numFlagChange = ([val], row: any) => {
// if (val == 'Y') {
// !row.numTitle && (row.numTitle = '尺码')
// } else {
// row.numTitle = ''
// }
}
const validateNumTitle = () => {
if (unref(excelAreaTitle).some((v) => v.numFlag == 'Y' && !v.numTitle)) {
ElMessage.error('拆分的单元格需要设置特性!')
return false
}
return true
}
const save = () => {
// 验证是否标记了拆分,拆分的单元格必须设置numTitle字段
if (!validateNumTitle()) return
emits('next', -2, {
excelAreaTitle: unref(excelAreaTitle),
titleArea: unref(titleArea)
})
}
const delAreaTitle = (index: number, row: Recordable) => {
excelAreaTitle.value.splice(index, 1)
}
/**
* 重置标题区
* 1.重置表格数据,重置缓存标题区域
* 2.当前数据区标题区颜色
*/
const resetAreaTitle = () => {
titleArea.value.forEach((area: any) => {
luckysheet.menuButton.customUpdateFormat(
null,
'bg',
areaMarksColor['data'],
area.sr,
area.er,
area.sc,
area.ec,
false
)
})
resetExcelAreaTitleState()
}
const setAreaTitleBg = (type: 'head') => {
luckysheet.setRangeFormat('bg', areaMarksColor[type])
}
const resetExcelAreaTitleState = () => {
excelAreaTitle.value = []
titleArea.value = []
}
const nextStep = (index: number = 1) => {
// 验证是否设置标题区域
if (index > 0) {
if (!excelAreaTitle.value.length) {
return ElMessage.error('请添加标题区!')
}
if (!validateNumTitle()) return
}
emits(
'next',
index,
index > 0
? {
excelAreaTitle: unref(excelAreaTitle),
titleArea: unref(titleArea)
}
: undefined
)
// 返回重置表头标记
if (index < 0) {
resetAreaTitle()
}
}
defineExpose({
resetExcelAreaTitleState
})
</script>
<style lang="scss" scoped>
.excel-title-table {
padding: 8px;
}
</style>
<template>
<div class="w-full h-full bg-white p-4">
<p class="font-bold text-lg leading-10 border-b-2">订单项次列表</p>
<el-form class="pt-4" :inline="true" :model="formState">
<el-form-item>
<el-button type="primary" @click="onQuery">查询</el-button>
</el-form-item>
</el-form>
<div class="">
<vxe-table
ref="xTable"
size="small"
min-height="460"
border
:loading="loading"
:data="tableData"
>
<vxe-column type="expand" title="尺码" width="120">
<template #default>尺码信息</template>
<template #content="{ row }">
<div style="padding: 10px">
<vxe-table
:data="row.sizeList"
size="mini"
max-height="300px"
style="width: 300px"
>
<vxe-column field="size" title="尺码"></vxe-column>
<vxe-column field="num" title="尺码数量"></vxe-column>
</vxe-table>
</div>
</template>
</vxe-column>
<vxe-column field="orderNo" title="订单编码" width="120"></vxe-column>
<vxe-column field="rowNo" title="项次行" width="120"></vxe-column>
<vxe-column field="brandName" title="品牌名称" width="180"></vxe-column>
<vxe-column
field="customerName"
title="客户名称"
width="240"
></vxe-column>
<vxe-column
field="productType"
title="产品类型"
width="120"
></vxe-column>
<vxe-column
field="productCode"
title="产品编码"
width="120"
></vxe-column>
<vxe-column
field="productName"
title="产品名称"
width="240"
></vxe-column>
<vxe-column title="操作" width="240">
<template #default="{ row }">
<el-button type="text" size="small" @click="handleImportVar(row)"
>上传变量</el-button
>
<el-button type="text" size="small" @click="handleShowVarRun(row)"
>查看解析</el-button
>
</template>
</vxe-column>
</vxe-table>
<vxe-pager
size="small"
background
v-model:current-page="formState.currentPage"
v-model:page-size="formState.pageSize"
:total="formState.total"
@page-change="onQuery"
:layouts="[
'PrevPage',
'JumpNumber',
'NextPage',
'Sizes',
'FullJump',
'Total',
]"
>
</vxe-pager>
</div>
<vxe-modal
v-model="importVisible"
title="导入"
width="500px"
show-footer
@hide="imporModalHide"
:z-index="1000"
>
<el-form ref="importFormInstance" :model="importForm">
<el-form-item label="客户名称" prop="customerName">
<el-input v-model="importForm.customerName" disabled />
</el-form-item>
<el-form-item label="产品名称" prop="productName">
<el-input v-model="importForm.productName" type="textarea" disabled />
</el-form-item>
<el-form-item label="文件" prop="filePath">
<el-upload
action=""
ref="upload"
accept=".xlsx,.xls"
:on-remove="handleRemove"
:auto-upload="false"
:on-exceed="handleExceed"
:limit="9"
:on-change="changeUpload"
>
<el-button type="primary">上传文件</el-button>
<template #tip>
<div class="el-upload__tip">
选择你要上传的excel文件,仅支持xlsx、xls格式
</div>
</template>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="importVisible = false">取消</el-button>
<el-button type="primary" @click="submitImport">执行解析</el-button>
</template>
</vxe-modal>
<TemplateVariable v-model:visible="tempVisible" v-bind="detailVariable" />
</div>
</template>
<script lang="ts" setup>
import { nextTick, onMounted, reactive, ref } from "vue";
import {
apiOrderVarPage,
apiOrderVarGetVars,
apiOrderVarGetNewVars,
apiOrderVarSaveUpload,
apiOrderVarRun,
} from "@/api/var";
import type { VxeTableInstance } from "vxe-table";
import TemplateVariable from "./components/TemplateVariable.vue";
import { filterRunData2 } from "@/utils/excel";
import { uploadFile } from "@/api/excel";
import { ElMessage } from "element-plus";
const loading = ref(false);
const formState = reactive({
currentPage: 1,
pageSize: 10,
total: 0,
// column: 'createTime',
// order: 'desc'
});
const xTable = ref<VxeTableInstance>();
const tableData = ref([]);
const tempVisible = ref(false);
const detailVariable = ref({
title: "变量文件解析",
titles: [],
data: [],
});
const handleShowVarRun = async (row: any) => {
const {data} = await apiOrderVarGetNewVars(row.orderItemId);
const { res, titles } = filterRunData2(data.result || [], false);
detailVariable.value.titles = titles;
detailVariable.value.data = res;
tempVisible.value = true;
};
const importVisible = ref(false);
const importForm = ref({
customerName: "",
productName: "",
productCode: "",
customerId: "",
orderItemId: "",
filePaths: [],
});
const handleImportVar = async (row) => {
importForm.value.customerName = row.customerName;
importForm.value.productName = row.productName;
importForm.value.customerId = row.customerId;
importForm.value.productCode = row.productCode;
importForm.value.orderItemId = row.orderItemId;
importVisible.value = true;
};
const imporModalHide = () => {
importForm.value.filePaths = [];
};
const handleRemove = (file) => {
importForm.value.filePaths = importForm.value.filePaths.filter(
(item) => item.uid !== file.uid
);
};
const handleExceed = () => {};
const changeUpload = (file: any) => {
const formData = new FormData();
formData.append("file", file.raw);
console.log(file, "file");
uploadFile(formData).then(({ data }) => {
if (data?.code === 200) {
importForm.value.filePaths.push({ uid: file.uid, path: data.message });
} else {
return ElMessage.error("上传失败!");
}
});
};
const submitImport = async () => {
const params = {
...importForm.value,
filePaths: importForm.value.filePaths.map((item) => item.path),
};
await apiOrderVarSaveUpload(params);
const { data } = await apiOrderVarRun(importForm.value.orderItemId);
if (data?.code == "200") {
ElMessage.success(data.message || "解析成功!");
importVisible.value = false;
onQuery();
nextTick(() => {
handleShowVarRun(importForm.value);
});
} else {
ElMessage.error(data.message || "解析失败!");
}
};
const onQuery = async () => {
loading.value = true;
try {
const { data } = await apiOrderVarPage(formState);
tableData.value = data.result.records;
formState.total = +data.result.total;
} catch {}
loading.value = false;
};
onMounted(() => {
onQuery();
});
</script>
<style lang="scss" scoped></style>
<template>
<vxe-modal
v-model="showEdit"
:z-index="1006"
@hide="onHide"
title="客户选择"
width="800"
esc-closable
mask-closable
show-footer
>
<template #default>
<vxe-table ref="xTable" border :data="data" size="small" height="400">
<vxe-column v-for="column in titles" :key="item" :field="column" :title="column"></vxe-column>
</vxe-table>
</template>
<template #footer>
<el-button type="primary" @click="showEdit = false">关闭</el-button>
</template>
</vxe-modal>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted, reactive, watch, unref } from 'vue'
import { getCustomerPage } from '@/api/customer'
import type { VxeTableInstance } from 'vxe-table'
import { ElMessage } from 'element-plus'
export default defineComponent({
name: 'TemplateVariables',
props: {
visible: {
type: Boolean,
default: false
},
titles: {
type: Array,
default: () => []
},
data: {
type: Array,
default: () => []
}
},
emits: ['update:visible'],
setup(props, { emit }) {
const showEdit = ref(false)
const xTable = ref<VxeTableInstance>()
const tableData = ref([])
watch(
() => props.visible,
(val) => {
showEdit.value = val
}
)
const onHide = () => {
emit('update:visible', false)
}
return {
showEdit,
xTable,
tableData,
onHide,
}
}
})
</script>
<style lang="scss" scoped></style>
\ No newline at end of file
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