This commit is contained in:
2026-05-05 16:35:30 +08:00
parent ed0d1aaacf
commit 2b63fe4147
19 changed files with 777 additions and 121 deletions
+8
View File
@@ -0,0 +1,8 @@
import request from "@/utils/request";
export function getProductPrice(data) {
return request({
url: "/product/getPrice",
method: "post",
data: data,
});
}
+27 -33
View File
@@ -1,11 +1,5 @@
<template>
<el-image
:src="`${realSrc}`"
fit="cover"
:style="`width:${realWidth};height:${realHeight};`"
:preview-src-list="realSrcList"
preview-teleported
>
<el-image :src="`${realSrc}`" :fit="fit" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="realSrcList" preview-teleported>
<template #error>
<div class="image-slot">
<el-icon><picture-filled /></el-icon>
@@ -15,56 +9,56 @@
</template>
<script setup>
import { isExternal } from "@/utils/validate"
import { isExternal } from "@/utils/validate";
const props = defineProps({
src: {
type: String,
default: ""
default: "",
},
fit: {
type: String,
default: "cover",
},
width: {
type: [Number, String],
default: ""
default: "",
},
height: {
type: [Number, String],
default: ""
}
})
default: "",
},
});
const realSrc = computed(() => {
if (!props.src) {
return
return;
}
let real_src = props.src.split(",")[0]
let real_src = props.src.split(",")[0];
if (isExternal(real_src)) {
return real_src
return real_src;
}
return import.meta.env.VITE_APP_BASE_API + real_src
})
return import.meta.env.VITE_APP_BASE_API + real_src;
});
const realSrcList = computed(() => {
if (!props.src) {
return
return;
}
let real_src_list = props.src.split(",")
let srcList = []
real_src_list.forEach(item => {
let real_src_list = props.src.split(",");
let srcList = [];
real_src_list.forEach((item) => {
if (isExternal(item)) {
return srcList.push(item)
return srcList.push(item);
}
return srcList.push(import.meta.env.VITE_APP_BASE_API + item)
})
return srcList
})
return srcList.push(import.meta.env.VITE_APP_BASE_API + item);
});
return srcList;
});
const realWidth = computed(() =>
typeof props.width == "string" ? props.width : `${props.width}px`
)
const realWidth = computed(() => (typeof props.width == "string" ? props.width : `${props.width}px`));
const realHeight = computed(() =>
typeof props.height == "string" ? props.height : `${props.height}px`
)
const realHeight = computed(() => (typeof props.height == "string" ? props.height : `${props.height}px`));
</script>
<style lang="scss" scoped>
@@ -0,0 +1,27 @@
<template>
<el-carousel height="600px" indicator-position="outside" trigger="click">
<el-carousel-item v-for="item in images" :key="item" style="display: flex; align-items: center; justify-content: center">
<el-image :src="item" fit="contain" width="100%" height="100%" loading="lazy" :preview-src-list="images" preview-teleported close-on-press-escape hide-on-click-modal></el-image>
</el-carousel-item>
</el-carousel>
<view>
<text v-if="remark" style="color: red; font-weight: bold; font-size: 18px; white-space: pre-line"> 预计发货时间:<br />{{ remark }}</text>
</view>
</template>
<script setup>
import { ref, watch } from "vue";
const props = defineProps({
images: {
type: Array,
required: true,
default: () => [],
},
remark: {
type: String,
default: "",
},
});
const localData = ref(props.modelValue);
</script>
@@ -0,0 +1,36 @@
<template>
<el-input v-model="localData" type="text" @input="changeValue" style="width: 100px">
<template #append v-if="$slots.append"> <slot name="append" /></template>
<template #prefix v-if="$slots.prefix"> <slot name="prefix" /></template>
<template #suffix v-if="$slots.suffix"> <slot name="suffix" /></template>
<template #prepend v-if="$slots.prepend"> <slot name="prepend" /></template>
</el-input>
</template>
<script setup>
import { ref, watch } from "vue";
const props = defineProps({
modelValue: {
type: String,
required: true,
default: () => "",
},
});
const emits = defineEmits(["update:modelValue"]);
const localData = ref(props.modelValue);
watch(
() => props.modelValue,
(val) => {
if (val && val.length > 0) {
localData.value = JSON.parse(JSON.stringify(val));
}
},
{ deep: true, immediate: true },
);
const changeValue = (val) => {
localData.value = val.replace(/[^0-9.]/g, ""); // 只保留数字和小数点
emits("update:modelValue", localData.value);
};
</script>
@@ -0,0 +1,46 @@
<template>
<view class="result-container">
<el-button type="primary" @click="handleGetPrice">获取价格</el-button>
<el-input type="textarea" style="width: 400px; height: 400px" rows="10" resize="none" readonly></el-input>
</view>
</template>
<script setup>
import { ref, watch } from "vue";
import { ElMessage } from "element-plus";
import { getProductPrice } from "@/api/product/index.js";
const props = defineProps({
data: {
type: Object,
required: true,
},
});
const emits = defineEmits(["verifyCraftData"]);
const handleGetPrice = () => {
emits("verifyCraftData", (result) => {
let { valid, message } = result;
if (!valid) {
ElMessage({
message: message || "报价数据验证失败",
type: "error",
grouping: true,
});
return;
}
getProductPrice(props.data).then((res) => {
console.log(res);
});
});
};
</script>
<style lang="scss" scoped>
.result-container {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 20px;
}
</style>
@@ -11,7 +11,7 @@
<el-select v-if="child.type === 'select'" v-model="child.value" @change="emitChange('child', { itemIndex: index, optionValue: option.value, childKey: key, value: $event })" style="width: 150px">
<el-option v-for="opt in child.options" :key="opt.value" :value="opt.value" :label="opt.label"></el-option>
</el-select>
<el-input v-else-if="child.type === 'input'" :placeholder="child.placeholder" v-model="child.value" @change="emitChange('child', { itemIndex: index, optionValue: option.value, childKey: key, value: $event })" style="width: 100px"></el-input>
<number-input v-else-if="child.type === 'input'" :placeholder="child.placeholder" v-model="child.value" @change="emitChange('child', { itemIndex: index, optionValue: option.value, childKey: key, value: $event })" style="width: 100px"></number-input>
</template>
</template>
</template>
@@ -22,7 +22,9 @@
</template>
<script setup>
import { ref, watch, onMounted, defineEmits, defineProps } from "vue";
import { ref, watch, onMounted, defineProps } from "vue";
import NumberInput from "@/components/NumberInput";
const props = defineProps({
data: {
@@ -3,7 +3,7 @@
</template>
<script setup>
import { ref, watch, defineEmits, defineProps } from "vue";
import { ref } from "vue";
import ProductCraft from "@/components/ProductCraft";
const defaultCraftData = ref([
@@ -156,6 +156,8 @@ const defaultCraftData = ref([
},
]);
const emits = defineEmits(["update:modelValue"]);
const handleCraftChange = (info) => {
const { optionValue, itemIndex, data } = info;
const currentItem = data[itemIndex];
@@ -164,7 +166,9 @@ const handleCraftChange = (info) => {
currentItem.options.forEach((opt) => {
if (opt.value === optionValue) {
} else {
opt.checked = false;
if (itemIndex != 5) {
opt.checked = false;
}
}
});
@@ -197,13 +201,50 @@ const handleCraftChange = (info) => {
// 3. 更新响应式数据
defaultCraftData.value = data;
handleDataInfo();
};
//处理工艺数据
const handleDataInfo = () => {
let datainfo = [];
defaultCraftData.value.forEach((craft) => {
const selectedOption = craft.options.filter((opt) => {
return opt.checked;
});
if (selectedOption && selectedOption.length > 0) {
selectedOption.forEach((opt) => {
let item = {};
if (opt.checked) {
item.type = opt.label;
item.value = opt.value;
if (opt.children) {
let childItem = {};
item.children = [];
opt.children.forEach((child) => {
if (child.id && child.value) {
childItem[child.id] = child.value;
} else {
childItem.value = child.value;
}
});
item.children.push(childItem);
}
}
datainfo.push(item);
});
}
});
emits("update:modelValue", datainfo);
};
const verifyCraftData = () => {
// 验证工艺数据的完整性和正确性
return { valid: true };
return { valid: false, message: "工艺数据验证失败" };
};
handleDataInfo();
defineExpose({
verifyCraftData,
});
+195 -80
View File
@@ -1,46 +1,51 @@
<template>
<view class="container">
<h1 style="font-weight: bold">不干胶</h1>
<el-form>
<el-form-item>
<el-radio-group v-model="data.types" @change="handleChange">
<el-radio label="常用种类" value="常用种类" size="large" border />
<el-radio label="专版打印" value="专版打印" size="large" border />
</el-radio-group>
</el-form-item>
<view class="form-title">品种</view>
<el-form-item>
<el-select v-model="data.material" placeholder="请选择" size="large" style="width: 300px">
<template v-for="item in materials" :key="item.name">
<el-option :label="item.name" :value="item.name"></el-option>
</template>
</el-select>
</el-form-item>
<view class="form-title">尺寸</view>
<el-form-item>
<el-input style="width: 150px" v-model="data.size[0]" type="number">
<template #append> <text>cm</text></template>
</el-input>
<text style="margin: 0 10px">X</text>
<el-input style="width: 150px" v-model="data.size[1]" type="number">
<template #append> <text>cm</text> </template>
</el-input>
</el-form-item>
<view class="form-title">个数</view>
<el-form-item>
<el-input style="width: 300px" v-model="data.count" type="number" placeholder="请输入数量" size="large"></el-input>
</el-form-item>
<view class="form-title">款数</view>
<el-form-item>
<el-input style="width: 300px" v-model="data.number" type="number" placeholder="请输入数量" size="large"></el-input>
</el-form-item>
<view class="form-title">客户旺旺</view>
<el-form-item>
<el-input style="width: 300px" v-model="data.customerWw" placeholder="请输入客户旺旺" size="large"></el-input>
</el-form-item>
<component v-if="currentCraftComponent" :is="currentCraftComponent" ref="componentRef" />
<el-button type="primary" @click="handlesave">保存</el-button>
</el-form>
<view class="left-info">
<h1 style="font-weight: bold">不干胶</h1>
<el-form>
<el-form-item>
<el-radio-group v-model="data.types" @change="handleChange">
<el-radio label="常用种类" value="常用种类" size="large" border />
<el-radio label="专版打印" value="专版打印" size="large" border />
</el-radio-group>
</el-form-item>
<view class="form-title">品种</view>
<el-form-item>
<el-select v-model="data.material" placeholder="请选择" size="large" style="width: 300px">
<template v-for="item in materials" :key="item.name">
<el-option :label="item.name" :value="item.name"></el-option>
</template>
</el-select>
</el-form-item>
<view class="form-title">尺寸</view>
<el-form-item>
<number-input style="width: 150px" v-model="data['length']">
<template #append> <text>cm</text></template>
</number-input>
<text style="margin: 0 10px">X</text>
<number-input style="width: 150px" v-model="data['width']">
<template #append> <text>cm</text> </template>
</number-input>
</el-form-item>
<view class="form-title">个数</view>
<el-form-item>
<number-input style="width: 300px" v-model="data.count" placeholder="请输入数量" size="large"></number-input>
</el-form-item>
<view class="form-title">款数</view>
<el-form-item>
<number-input style="width: 300px" v-model="data.number" placeholder="请输入数量" size="large"></number-input>
</el-form-item>
<view class="form-title">客户旺旺</view>
<el-form-item>
<el-input style="width: 300px" v-model="data.customerWw" placeholder="请输入客户旺旺" size="large"></el-input>
</el-form-item>
<component v-if="currentCraftComponent" :is="currentCraftComponent" ref="componentRef" v-model="data.crafts" />
<PriceResult :data="data" @verifyCraftData="handleVerifyCraftData" />
</el-form>
</view>
<view class="right-image">
<ImageRemark :images="images" :remark="remark" />
</view>
</view>
</template>
<script setup>
@@ -48,30 +53,100 @@ import { ref, watch, shallowRef } from "vue";
import copperplate from "./crafts/copperplate.vue";
import pvc from "./crafts/pvc.vue";
import transparent from "./crafts/transparent.vue";
import NumberInput from "@/components/NumberInput";
import ImageRemark from "@/components/ImageRemark";
import PriceResult from "@/components/PriceResult";
const materials = [
{ name: "铜板纸不干胶", images: "" },
{ name: "pvc不干胶", images: "" },
{ name: "透明不干胶", images: "" },
{ name: "牛皮纸", images: "" },
{ name: "哑金不干胶", images: "" },
{ name: "哑银不干胶", images: "" },
{ name: "书写纸不干胶", images: "" },
{ name: "银平光", images: "" },
{ name: "拉丝金", images: "" },
{ name: "拉丝银", images: "" },
{ name: "美纹纸", images: "" },
{ name: "PP合成纸", images: "" },
{ name: "易碎纸不干胶", images: "" },
{ name: "刚古水纹超白", images: "" },
{ name: "红底散金", images: "" },
{ name: "布纹纸超白", images: "" },
{ name: "珠光超白", images: "" },
{ name: "10C静电膜", images: "" },
{ name: "树纹纸", images: "" },
{ name: "草香纸/大地纸", images: "" },
{ name: "单防热敏纸(底纸白色)", images: "" },
{ name: "三防热敏纸(底纸蓝色)", images: "" },
{
name: "铜板纸不干胶",
images: ["https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E9%93%9C%E7%89%88%E7%BA%B8%E4%B8%8D%E5%B9%B2%E8%83%B6/%E4%BA%AE%E8%86%9C.jpg"],
remark: "广东:数量500-1000张(顺丰14点前当天发货 普通快递16点前当天发货) 中通 圆通 顺丰;\n江苏:(3-4天发货) 韵达 顺丰;",
},
{
name: "pvc不干胶",
images: ["https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E8%A6%86%E4%BA%AE%E8%86%9C.jpg"],
},
{
name: "透明不干胶",
images: ["https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E9%80%8F%E6%98%8E%E4%B8%8D%E5%B9%B2%E8%83%B6/%E4%BA%AE%E8%86%9C.jpg"],
},
{
name: "牛皮纸",
images: ["https://offer.lingtao8.com/upImg/upload/product/20210722/不干胶-牛皮纸不干胶.jpg"],
},
{
name: "哑金不干胶",
images: ["https://offer.lingtao8.com/upImg/upload/product/20210722/不干胶-哑金.jpg", "https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E5%93%91%E9%87%91%E4%B8%8D%E5%B9%B2%E8%83%B6/%E5%93%91%E9%87%91%E4%B8%8D%E5%B9%B2%E8%83%B6%E5%8D%B0%E5%88%B71%E8%89%B2.jpg", "https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E5%93%91%E9%87%91%E4%B8%8D%E5%B9%B2%E8%83%B6/%E5%93%91%E9%87%91%E4%B8%8D%E5%B9%B2%E8%83%B6%E5%8A%A0%E5%87%B9%E5%87%B8.jpg", "https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E5%93%91%E9%87%91%E4%B8%8D%E5%B9%B2%E8%83%B6/%E5%93%91%E9%87%91%E4%B8%8D%E5%B9%B2%E8%83%B6%E5%8D%B02%E8%89%B2.jpg"],
},
{
name: "哑银不干胶",
images: ["https://offer.lingtao8.com/upImg/upload/product/20210722/不干胶-哑银.jpg", "https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E5%93%91%E9%93%B6%E4%B8%8D%E5%B9%B2%E8%83%B6/%E5%93%91%E9%87%91%E4%B8%8D%E5%B9%B2%E8%83%B6%E5%8D%B01%E8%89%B2.jpg", "https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E5%93%91%E9%93%B6%E4%B8%8D%E5%B9%B2%E8%83%B6/%E5%93%91%E9%93%B6%E4%B8%8D%E5%B9%B2%E8%83%B6%E5%8A%A0%E5%87%B9%E5%87%B8.jpg"],
},
{
name: "书写纸不干胶",
images: ["https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E4%B9%A6%E5%86%99%E7%BA%B8%E4%B8%8D%E5%B9%B2%E8%83%B6.jpeg"],
},
{
name: "银平光",
images: ["https://offer.lingtao8.com/upImg/upload/product/20210722/不干胶-银平光.jpg"],
},
{
name: "拉丝金",
images: ["https://offer.lingtao8.com/upImg/upload/product/20210722/不干胶-拉丝金.jpg"],
},
{
name: "拉丝银",
images: ["https://offer.lingtao8.com/upImg/upload/product/20210722/不干胶-拉丝银.jpg", "https://offer.lingtao8.com/upImg/upload/product/20210722/不干胶-拉丝银 (2).jpg"],
},
{
name: "美纹纸",
images: ["https://offer.lingtao8.com/upImg/upload/product/20210722/不干胶-美纹纸.jpg"],
},
{
name: "PP合成纸",
images: ["https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/PP%E5%90%88%E6%88%90%E7%BA%B8.png"],
},
{
name: "易碎纸不干胶",
images: ["https://offer.lingtao8.com/upImg/upload/product/20210722/易碎贴.jpg", "https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E6%98%93%E7%A2%8E%E7%BA%B8%E4%B8%8D%E5%B9%B2%E8%83%B6.jpg"],
},
{
name: "刚古水纹超白",
images: ["https://offer.lingtao8.com/upImg/upload/product/20220323/刚古水纹超白.png"],
},
{
name: "红底散金",
images: ["https://offer.lingtao8.com/upImg/upload/product/20220323/红底散金.png"],
},
{
name: "布纹纸超白",
images: ["https://offer.lingtao8.com/upImg/upload/product/20220323/布纹纸超白.png"],
},
{
name: "珠光超白",
images: ["https://offer.lingtao8.com/upImg/upload/product/20220323/珠光超白.png"],
},
{
name: "10C静电膜",
images: ["https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/10C%E9%9D%99%E7%94%B5%E8%86%9C.png"],
},
{
name: "树纹纸",
images: ["https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/swz/%E6%BF%80%E5%87%B8.png"],
},
{
name: "草香纸/大地纸",
images: ["https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E5%A4%A7%E5%9C%B0%E7%BA%B8%E6%BF%80%E5%87%B8.png"],
},
{
name: "单防热敏纸(底纸白色)",
images: ["https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E5%8D%95%E9%98%B2%E7%83%AD%E6%95%8F%E7%BA%B8%EF%BC%88%E5%BA%95%E7%BA%B8%E7%99%BD%E8%89%B2%EF%BC%89.png"],
},
{
name: "三防热敏纸(底纸蓝色)",
images: ["https://ltcloudfile.oss-cn-hangzhou.aliyuncs.com/price_img/20240229/%E4%B8%89%E9%98%B2%E7%83%AD%E6%95%8F%E7%BA%B8%EF%BC%88%E5%BA%95%E7%BA%B8%E8%93%9D%E8%89%B2%EF%BC%89.png"],
},
];
const craftMap = {
@@ -81,32 +156,25 @@ const craftMap = {
};
const currentCraftComponent = shallowRef(null);
const componentRef = ref(null);
const handlesave = () => {
console.log(data.value);
if (typeof componentRef.value?.verifyCraftData === "function") {
let { valid, message } = componentRef.value.verifyCraftData();
if (!valid) {
console.error("工艺数据验证失败:", message);
return;
}
}
};
const images = ref([]);
const remark = ref("");
const data = ref({
types: "常用种类",
material: "",
size: [],
length: null,
width: null,
count: null,
number: 1,
customerWw: "",
craft: [],
crafts: [],
});
watch(
() => data.value.material,
(mat) => {
handleGetImages(mat);
currentCraftComponent.value = craftMap[mat] || null;
data.value.craft = [];
data.value.crafts = [];
},
);
@@ -114,14 +182,56 @@ const handleChange = (val) => {
const initData = {
types: val,
material: "",
size: [],
length: null,
width: null,
count: null,
number: 1,
customerWw: "",
craft: [],
crafts: [],
};
data.value = initData;
};
const handleGetImages = (name) => {
images.value = [];
if (name) {
let item = materials.find((item) => item.name === name) || {
images: [],
};
images.value = item.images;
} else {
materials.forEach((item) => {
images.value.push(...item.images);
});
}
remark.value = materials.find((item) => item.name === name)?.remark || "";
};
const handleVerifyCraftData = (callback) => {
if (data.value.material == "") {
callback({ valid: false, message: "请选择材质" });
return;
}
if (!data.value.width) {
callback({ valid: false, message: "请输入宽度" });
return;
}
if (!data.value.length) {
callback({ valid: false, message: "请输入长度" });
return;
}
if (!data.value.count) {
callback({ valid: false, message: "请输入数量" });
return;
}
if (typeof componentRef.value?.verifyCraftData === "function") {
let { valid, message } = componentRef.value.verifyCraftData();
callback({ valid, message });
return;
}
callback({ valid: true, message: "工艺数据验证通过" });
};
handleGetImages();
</script>
<style lang="scss" scoped>
.el-form-item--default {
@@ -130,7 +240,6 @@ const handleChange = (val) => {
.container {
margin: 0 20px;
display: flex;
flex-direction: column;
}
.form-title {
display: block;
@@ -138,4 +247,10 @@ const handleChange = (val) => {
font-size: 16px;
margin-bottom: 5px;
}
.left-info {
flex: 1;
}
.right-image {
flex: 1;
}
</style>