123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 |
- <template>
- <el-card class="step-card">
- <div
- slot="header"
- class="flex between">
- <div class="step-card-title">Step1 Choose model</div>
- <div>>></div>
- </div>
- <div v-loading="loading">
- <div class="card-sub-title">{{ detail.product_name }}</div>
- <image-viewer
- v-if="isBigImageShow"
- :on-close="closeBigImage"
- :initial-index="0"
- :url-list="detail.main?.images" />
- <div
- class="img-wrap flex center"
- @click="openBigImage">
- <img :src="detail.main?.image" />
- </div>
- <div class="divider"></div>
- <el-form
- :model="form"
- :rules="rules"
- label-width="90px"
- ref="form">
- <el-form-item
- label="Time frame"
- prop="cycle">
- <el-radio-group v-model="form.cycle">
- <el-radio
- v-for="item in priceData.priceList"
- :key="item.cycle_id"
- :label="item.cycle_id"
- >{{ item.name }}
- </el-radio>
- </el-radio-group>
- </el-form-item>
- <div class="flex">
- <el-form-item
- label-width="120px"
- label="Decorated in"
- prop="decorated">
- <el-select
- v-model="form.decorated"
- size="small">
- <el-option
- :label="'Local'"
- :value="'Local'"></el-option>
- <el-option
- :label="'China'"
- :value="'China'"></el-option>
- </el-select>
- </el-form-item>
- <el-form-item
- label-width="120px"
- prop="supplyChain"
- label="Supply chain"
- size="small">
- <el-select v-model="form.supplyChain">
- <el-option
- :label="'AU Stock'"
- :value="'AU Stock'"></el-option>
- <el-option
- :label="'Air Freight'"
- :value="'Air Freight'"></el-option>
- <el-option
- :label="'Sea Freight'"
- :value="'Sea Freight'"></el-option>
- </el-select>
- </el-form-item>
- </div>
- <el-form-item
- label="Model"
- prop="model">
- <div class="custom-checkbox-wrap">
- <div
- class="custom-checkbox"
- :class="{
- active: form.model === item.id,
- disable: form.model && form.model !== item.id,
- }"
- v-for="item in computedBasePriceData"
- @click="modelClick(item)"
- :key="item.id">
- {{ item.point }}
- </div>
- </div>
- <el-radio-group
- v-model="form.model"
- style="display: none"
- size="small">
- <el-radio-button
- v-for="item in computedBasePriceData"
- :key="item.id"
- :label="item.id"
- >{{ item.point }}</el-radio-button
- >
- </el-radio-group>
- </el-form-item>
- <el-form-item
- label="Colour"
- prop="color">
- <div class="custom-checkbox-wrap">
- <div
- class="custom-checkbox"
- :class="{
- active: form.color.includes(0),
- }"
- @click="colorClick({ id: 0 })">
- Unspecified
- </div>
- <div
- class="custom-checkbox flex"
- :class="{
- active: form.color.includes(item.id),
- }"
- v-for="item in detail.color"
- @click="colorClick(item)"
- :key="item.id">
- <div class="color-selector-label flex center">
- <img :src="item.img" />
- </div>
- <div>
- {{ item.name }}
- </div>
- </div>
- <div
- class="custom-checkbox"
- :class="{
- active: form.color.includes(999),
- }"
- @click="colorClick({ id: 999 })">
- + PMS
- </div>
- </div>
- <el-checkbox-group
- v-model="form.color"
- style="display: none"
- size="small">
- <el-checkbox-button :label="0">Unspecified</el-checkbox-button>
- <el-checkbox-button
- v-for="item in detail.color"
- :label="item.id"
- :key="item.id">
- {{ item.name }}
- </el-checkbox-button>
- <el-checkbox-button :label="999">+ PMS</el-checkbox-button>
- </el-checkbox-group>
- </el-form-item>
- <el-form-item prop="colorPmsText">
- <el-input
- v-show="form.color.includes(999)"
- type="textarea"
- :rows="5"
- placeholder="Product color comments. Multi color instructions, specific color matchong (CMYK, RGB, PMS) etc.."
- v-model="form.colorPmsText">
- </el-input>
- </el-form-item>
- <div class="qty-title">
- QTY ( MOQ:{{ computedMinBuyNumber }} )
- </div>
- <div
- class="divider"
- v-show="form.color.length > 0"></div>
- <div class="flex wrap">
- <el-form-item
- class="flex-auto color-form-item"
- label-width="140"
- v-for="(formItem, index) in form.autoForm"
- :prop="`autoForm.${index}.value`"
- :rules="{
- required: true,
- trigger: 'change',
- type: 'number',
- message: 'the number should not less then MOQ',
- min: computedMinBuyNumber,
- }"
- :key="index">
- <div class="flex end">
- <div class="flex-auto flex end">
- <img
- class="auto-form-color-image"
- v-if="formItem.img"
- :src="formItem.img"
- alt="" />
- <div class="auto-form-label form-item-label">
- {{ formItem.label }}
- </div>
- </div>
- <el-input
- @change="
- value => {
- if (value >= computedMinBuyNumber)
- $refs.form.clearValidate(`autoForm.${index}.value`)
- }
- "
- style="width: 80px"
- :min="computedMinBuyNumber"
- type="number"
- v-model.number="formItem.value"></el-input>
- </div>
- </el-form-item>
- </div>
- </el-form>
- </div>
- </el-card>
- </template>
- <script>
- import imageViewer from 'element-ui/packages/image/src/image-viewer'
- import stepMixin from './stepMixin'
- export default {
- name: 'Step1',
- components: {
- 'image-viewer': imageViewer,
- },
- mixins: [stepMixin],
- props: {
- // 步骤2的表单. 因其打印价格表单会反向影响本组件的最小起购数量, 故需从父组件获取. 只用来计算, 本组件不更改这个数据.
- form2: {
- type: Object,
- default: function () {
- return {}
- },
- },
- },
- data() {
- // this.detail 记录在mixin里;
- return {
- // 查看大图
- isBigImageShow: false,
- rules: {
- decorated: [{ required: true, message: '请选择', trigger: 'change' }],
- supplyChain: [{ required: true, message: '请选择', trigger: 'change' }],
- model: [
- {
- required: true,
- trigger: 'change',
- type: 'number',
- min: 1,
- message: 'Please select model',
- },
- ],
- color: [
- {
- required: true,
- validator: (rules, value, cb) => {
- value.length > 0
- ? cb()
- : cb(new Error('Please select at least one color'))
- },
- trigger: 'change',
- },
- ],
- colorPmsText: [{ trigger: 'blur', validator: this.checkColorPmsText }],
- cycle: [
- {
- required: true,
- message: 'Please select time frame',
- trigger: 'change',
- },
- ],
- },
- form: {
- // 必须要有的初始值, 否则必定会报错Cannot read properties of undefined
- color: [],
- model: 0,
- colorPmsText: '',
- },
- // 标志符,用于控制监听是否启用
- loaded: false,
- }
- },
- computed: {
- // 商品 当前选中周期的 基础价格和打印价格数据
- computedPriceData() {
- return this.priceData.priceList.filter(
- item => item.cycle_id === this.form.cycle
- )
- },
- // 当前选中周期下, 商品对应的各型号基础价格数据. 可以推断当前周期有几个型号
- computedBasePriceData() {
- const model = this.computedPriceData.length
- ? this.computedPriceData[0]
- : {}
- // 属性‘1’里面是基础价格数据, 属性 ’2‘是打印价格数据
- if (model['1']) {
- return model['1'].slice()
- } else {
- return []
- }
- },
- // 当前型号位于基础价格数据的index, 用于取出型号对应的基础数据
- computedBasePriceIndex() {
- return this.computedBasePriceData.findIndex(
- item => item.id === this.form.model
- )
- },
- // 该商品周期的最小起订量. attributeList的属性名(website_qty1, website_qty2)排序, 然后取属性值
- computedMinBuyNumber() {
- // 算基础价格的第一个有效值
- const target = this.computedBasePriceData.length
- ? this.computedBasePriceData[
- this.computedBasePriceIndex > 0 ? this.computedBasePriceIndex : 0
- ]
- : {}
- const candidate = [
- target.website_qty1,
- target.website_qty2,
- target.website_qty3,
- target.website_qty4,
- target.website_qty5,
- target.website_qty6,
- target.website_qty7,
- target.website_qty8,
- ]
- if (!candidate.some(item => item !== undefined)) return 1
- // 算出商品基础价格的第一个有效值
- let index = this.findEffectIndex(candidate)
- // 算出打印服务和附加服务的第一个有效价格所处位置.
- Object.entries(this.form2).forEach(current => {
- if (/\d+/.test(current[0])) {
- const decoration = current[1].decorationList.filter(
- i => i.id === current[1].printService
- )
- if (decoration.length && current[1].enable) {
- // 打印价格的基础阶梯价格
- const index2 = this.findEffectIndex([
- decoration[0].website_qty1,
- decoration[0].website_qty2,
- decoration[0].website_qty3,
- decoration[0].website_qty4,
- decoration[0].website_qty5,
- decoration[0].website_qty6,
- decoration[0].website_qty7,
- decoration[0].website_qty8,
- ])
- // 附加价格
- const index3 = this.findEffectIndex([
- decoration[0].supplier_qty1,
- decoration[0].supplier_qty2,
- decoration[0].supplier_qty3,
- decoration[0].supplier_qty4,
- decoration[0].supplier_qty5,
- decoration[0].supplier_qty6,
- decoration[0].supplier_qty7,
- decoration[0].supplier_qty8,
- ])
- // 让index记录最大值
- if (index2 > index) index = index2
- if (index3 > index) index = index3
- }
- } else {
- // 附加服务的价格
- const additions = this.priceData.additionList[current[0]].filter(
- item => current[1].includes(item.id)
- )
- if (additions.length) {
- additions.forEach(target => {
- const index4 = this.findEffectIndex([
- target.website_qty1,
- target.website_qty2,
- target.website_qty3,
- target.website_qty4,
- target.website_qty5,
- target.website_qty6,
- target.website_qty7,
- target.website_qty8,
- ])
- // 让index记录最大值
- if (index4 > index) index = index4
- })
- }
- }
- })
- const temp = Object.entries(this.priceData.attributeList)
- .sort((a, b) => a[0].localeCompare(b[0]))
- .filter((item, i) => index === i)
- if (temp.length) {
- return temp[0][1]
- } else {
- return 1
- }
- },
- },
- watch: {
- computedBasePriceData() {
- if (!this.loaded || !this.computedBasePriceData.length) return
- // fixme 如果有从商品详情页带过来的型号选择数据, 要选中该值, 而不是默认的第一个值
- if (
- this.computedBasePriceData.filter(i => i.id === this.preData.model)
- .length
- ) {
- this.form.model = this.preData.model
- } else {
- this.form.model = this.computedBasePriceData[0].id
- }
- },
- 'form.model': {
- immediate: true,
- handler: function () {
- if (!this.loaded) return
- this.generateColorForm()
- },
- },
- 'form.color': {
- immediate: true,
- handler: function () {
- if (!this.loaded) return
- this.generateColorForm()
- this.$refs.form.clearValidate('colorPmsText')
- },
- },
- form2: {
- immediate: true,
- handler: function () {
- if (!this.loaded) return
- this.generateColorForm()
- },
- },
- },
- mounted() {
- this.form = {
- supplyChain: 'AU Stock',
- decorated: 'Local',
- model: 0, // 型号的赋值在computedBasePriceData的监听里面, 因为其涉及到基础价格变更后的重新赋值.
- cycle: this.preData.cycle
- ? this.preData.cycle
- : this.priceData.priceList[0].cycle_id,
- color: [],
- colorPmsText: '',
- // 根据所选规格和颜色组合成的自动表单.需要在computedBasePriceData的watch里面生成
- autoForm: [],
- }
- this.loaded = true
- },
- methods: {
- checkForm() {
- return new Promise((resolve, reject) => {
- this.$refs.form.validate(valid => {
- if (valid) {
- resolve(JSON.parse(JSON.stringify(this.form)))
- } else {
- reject(new Error('validate step1 form error'))
- }
- })
- })
- },
- checkColorPmsText(rule, value, cb) {
- // fixme. 颜色的两个固定值的id还未确定
- if (!this.form.color.includes(999)) cb()
- if (this.form.colorPmsText.trim().length < 1) {
- cb(new Error('You must type color comment here if "+ PMS" is checked'))
- } else {
- cb()
- }
- },
- // 找出第一个有效价格的index. 非变异方法, 勿对参数进行赋值操作.
- // 价格留空和111不算到起购量, 为正常数值或者0或者999(POA)就可以算到起购量, 所以在此处将空手动重置为NaN
- findEffectIndex(array) {
- return array
- .map(item => (item === '' ? Number.NaN : Number(item)))
- .findIndex(item => !Number.isNaN(item) && item !== 111)
- },
- openBigImage() {
- this.isBigImageShow = true
- },
- closeBigImage() {
- this.isBigImageShow = false
- },
- generateColorForm() {
- if (!this.loaded || this.form.color.length < 1) {
- this.form.autoForm = []
- return
- }
- // 生成所选规格和颜色组合成的自动表单
- const targetModel = this.computedBasePriceData.filter(
- item => item.id === this.form.model
- )
- const oldForm = JSON.parse(JSON.stringify(this.form.autoForm))
- let color1 = []
- if (targetModel.length) {
- color1 = this.detail.color.reduce((total, item) => {
- if (this.form.color.includes(item.id)) {
- const temp = {
- img: item.img || '',
- label: `${item.name}, ${targetModel[0].point}`,
- color: item.name,
- colorId: item.id,
- value: this.computedMinBuyNumber,
- }
- const temp2 = oldForm.filter(item => item.label === temp.label)
- if (temp2.length && temp2[0].value >= this.computedMinBuyNumber) {
- // 如果原来有值且原值大于等于最小起购, 则沿用原值
- temp.value = temp2[0].value
- }
- total.push(temp)
- }
- return total
- }, [])
- if (this.form.color.includes(0)) {
- const temp = {
- img: '',
- label: `Unspecified, ${targetModel[0].point}`,
- color: 'Unspecified',
- colorId: -1,
- value: this.computedMinBuyNumber,
- }
- const temp2 = oldForm.filter(item => {
- return item.label === temp.label
- })
- if (temp2.length && temp2[0].value >= this.computedMinBuyNumber) {
- // 如果原来有值且原值大于等于最小起购, 则沿用原值
- temp.value = temp2[0].value
- }
- color1.unshift(temp)
- }
- if (this.form.color.includes(999)) {
- const temp = {
- img: '',
- label: `+ PMS, ${targetModel[0].point}`,
- color: 'PMS',
- colorId: -1,
- value: this.computedMinBuyNumber,
- }
- const temp2 = oldForm.filter(item => item.label === temp.label)
- if (temp2.length && temp2[0].value >= this.computedMinBuyNumber) {
- // 如果原来有值且原值大于等于最小起购, 则沿用原值
- temp.value = temp2[0].value
- }
- color1.push(temp)
- }
- }
- this.$set(this.form, 'autoForm', color1)
- },
- modelClick(item) {
- if (this.form.model === item.id) {
- this.form.model = 0
- } else {
- this.form.model = item.id
- }
- },
- colorClick(item) {
- const index = this.form.color.indexOf(item.id)
- if (index !== -1) {
- this.form.color.splice(index, 1)
- } else {
- this.form.color.push(item.id)
- }
- },
- },
- }
- </script>
- <style lang="scss" scoped>
- @import './step.scss';
- div {
- box-sizing: border-box;
- }
- .img-wrap {
- $width: 140px;
- width: $width;
- height: $width;
- position: relative;
- padding: 4px;
- border: 1px solid #eee;
- cursor: pointer;
- margin-bottom: 16px;
- img {
- width: 100%;
- }
- }
- .el-checkbox-button {
- min-width: 76px;
- }
- .qty-title {
- margin-bottom: 16px;
- font-size: 14px;
- font-family: Proxima Nova, sans-serif;
- color: #000;
- }
- // 选择颜色
- .color-selector-label {
- width: 16px;
- height: 16px;
- position: relative;
- margin-right: 4px;
- img {
- width: 100%;
- }
- }
- // 颜色型号对应购买数量输入项
- .color-form-item {
- box-sizing: border-box;
- max-width: 50%;
- padding-left: 4px;
- .auto-form-label {
- text-align: right;
- padding: 0 12px;
- min-width: 140px;
- }
- :deep(.el-form-item__error) {
- text-align: right;
- width: 100%;
- }
- .auto-form-color-image {
- width: 20px;
- height: 20px;
- margin-right: -4px;
- }
- }
- </style>
|