<template> <div class="page"> <!-- {{props.props.propsData.isCad}} --> <div class="title">商品基础信息</div> <a-form style="margin-top: 30px" :model="formState" name="basic" :label-col="{ span: 1 }" :wrapper-col="{ span: 8 }" autocomplete="off" @finish="onFinish" @finishFailed="onFinishFailed"> <a-form-item label="商品名称" name="subject" :rules="rulesRef.subject" labelAlign="left" :label-col="{ span: 1 }"> <a-input v-model:value="formState.subject" /> </a-form-item> <a-form-item label="商品简介" name="shortname" :rules="rulesRef.shortname" labelAlign="left" :label-col="{ span: 1 }"> <a-input v-model:value="formState.shortname" /> </a-form-item> <a-form-item label=" 商品示图" name="picurl" :rules="rulesRef.picurl" :wrapper-col="{ offset: 0, span: 8 }" class="Up" labelAlign="left" :label-col="{ span: 1 }"> <div class="clearfix"> <a-upload class="clearfix-up" v-model:file-list="fileList" action="/api/file/upload" list-type="picture-card" @preview="handlePreview" @change="handleChange" :before-upload="beforeUpload"> <div v-if="fileList.length < 8"> <plus-outlined /> <div style="margin-top: 8px">Upload</div> </div> </a-upload> <a-modal :visible="previewVisible" :title="previewTitle" :footer="null" @cancel="handleCancel"> <img alt="example" style="width: 100%" :src="previewImage" /> </a-modal> <div> <p class="warin"> 建议图片比例为4:3,大小不超过200M,图片仅支持JPG、JPEG、PNG格式 </p> </div> </div> </a-form-item> <a-form-item label="商品详情" name="body" :rules="rulesRef.body" labelAlign="left" :label-col="{ span: 1 }"> <!-- <div style="display: none"> <a-upload action="https://www.mocky.io/v2/5cc8019d300000980a055e76" :multiple="true" :file-list="fileList" @change="handleChange"> <a-button> <upload-outlined></upload-outlined> Upload </a-button> </a-upload> <QuillEditor id="editorId" ref="myQuillEditor" v-model:content="content" theme="snow" contentType="html" :options="options" @blur="onEditorChange($event)" /> </div> --> <a-textarea v-model:value="formState.body" placeholder="请输入商品详情" :rows="4" /> <div class="editor-text"> <p>1、商品描述需符合《中华人民共和国广告法》</p> <p> 2、详情图片宽度750,高度不超过5000,每张图片最大不超过1M,图片仅支持JPG、JPEG、PNG格式。 </p> </div> </a-form-item> <a-form-item name="price" :wrapper-col="{ offset: 0, span: 2 }" label="商品售价" :rules="[{ required: true, message: '请输入输入价格' }]" labelAlign="left" :label-col="{ span: 1 }"> <div> <a-radio-group v-model:value="value" @change="onSelectPlain"> <a-radio :value="1">免费</a-radio> <a-radio :value="2">收费</a-radio> </a-radio-group> </div> </a-form-item> <a-form-item :wrapper-col="{ offset:2, span: 7 }" v-if="value === 2"> <div style="display:flex;"> <div style="margin-right:20px">划线价</div> <a-input-number v-model:value="formState.markingprice" style="width: 200px" :min="0" :max="10" :step="0.01" string-mode /> </div> </a-form-item> <a-form-item name="price" :wrapper-col="{ offset: 2, span: 7 }" v-if="value === 2" :rules="[{ required: true, message: '请输入商品价格!' }]"> <div style="display:flex;"> <div style="margin-right:20px">售卖价</div> <a-input-number v-model:value="formState.price" style="width: 200px" :min="0" :max="10" :step="0.01" string-mode /> </div> </a-form-item> <a-form-item :wrapper-col="{ offset: 0, span: 8 }"> <a-button type="primary" html-type="submit" @click="onSubmit">确定</a-button> </a-form-item> </a-form> </div> </template> <script lang="ts" setup> import { reactive, ref, defineEmits , defineExpose,toRaw } from "vue"; import { PlusOutlined } from "@ant-design/icons-vue"; import { message, UploadProps,Upload } from "ant-design-vue"; import { Form } from 'ant-design-vue'; // import { QuillEditor, Quill } from "@vueup/vue-quill"; import { onCreateGoods } from '@/api/index' // import "@vueup/vue-quill/dist/vue-quill.snow.css"; import { getUid } from "@/utils/userInfo"; const useForm = Form.useForm; interface FormState { subject: string, shortname: string; remember: boolean; body:string, picurl: string, markingprice: string, price: string, } function getBase64(file: File) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result); reader.onerror = (error) => reject(error); }); } const plainOptions = [ { label: "免费", value: true }, { label: "收费", value: true }, ]; const props = defineProps(); const emit = defineEmits(['onBack']); let content = ref(""); const myQuillEditor = ref(null); const crossedPrice = ref<Number>(1); const sellingPrice = ref<Number>(1); const value = ref<number>(1); const previewVisible = ref(false); const previewImage = ref(""); const previewTitle = ref(""); const fileList = ref<UploadProps["fileList"]>([ ]); const options = reactive({ modules: { toolbar: { container: [ [{ size: ["small", false, "large"] }], ["bold", "italic", "underline"], [{ header: 1 }, { header: 2 }], [{ list: "ordered" }, { list: "bullet" }], ["link", "image"], [{ color: [] }, { background: [] }], [{ align: [] }], ], handlers: { image: function (value: any) { if (value) { // 调用element图片上传 // document.querySelector(".editor-img-uploader>.el-upload").click(); } else { Quill.format("image", true); } }, }, }, history: { delay: 1000, maxStack: 50, userOnly: false, }, }, }); const handleCancel = () => { previewVisible.value = false; previewTitle.value = ""; }; const handlePreview = async (file: any) => { if (!file.url && !file.preview) { file.preview = (await getBase64(file.originFileObj)) as string; } previewImage.value = file.url || file.preview; previewVisible.value = true; previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf("/") + 1); }; const formState = reactive<FormState>({ subject: '', shortname: "", remember: true, body:"", picurl: "", markingprice: "", price: "", }); const rulesRef = reactive({ subject: [ { required: true, message: '请输入商品名称!', }, ], shortname: [ { required: true, message: '请输入商品简介!', }, ], body:[ { required: true, message: '请输入商品详情!', }, ], picurl: [ { validateOnRuleChange: true, message: '请上传商品示图!', }, ], markingprice: [ { required: true, message: '请输入划线价格', }, ], price: [ { required: true, message: '请输入售卖价格', }, ], }); const { resetFields, validate } = useForm(formState,rulesRef); const onFinish = (values: any) => { console.log("Success:", values); }; const onFinishFailed = (errorInfo: any) => { console.log("Failed:", errorInfo); }; const handleChange = (info: any) => { let resFileList = [...info.fileList]; // 1. Limit the number of uploaded files // Only to show two recent uploaded files, and old ones will be replaced by the new resFileList = resFileList.slice(-2); // 2. read from response and show file link resFileList = resFileList.map((file) => { if (file.response) { // Component will show file.url as link formState.picurl = file.response.data; } return file; }); fileList.value = resFileList; }; const onSelectPlain = (e: any) => { formState.price = "0" // free 0 value.value = e.target.value; }; const onEditorChange = (e:any)=>{ console.log(e.html,'e'); } const beforeUpload: UploadProps['beforeUpload'] = file => { if (!(file.type.includes('png')||file.type.includes('jpeg')||file.type.includes('jpg'))) { message.error(`${file.name}不是png/jpef/jpg格式`); return Upload.LIST_IGNORE; } }; const onSubmit =() => { validate() .then(async() => { const uid = getUid() const prarms = { ...toRaw(formState), uid, parent:1 } const data:any = await onCreateGoods(JSON.stringify(prarms)) if(data.state === 1){ resetFields() fileList.value = [] message.success(data.message) emit('onBack') } }) .catch(err => { console.log('error', err); }); }; defineExpose({ formState, onFinish, onFinishFailed, previewVisible, previewImage, fileList, handleCancel, handlePreview, previewTitle, options, content, handleChange, plainOptions, value, onSelectPlain, crossedPrice, sellingPrice, onSubmit, onEditorChange, beforeUpload }); </script> <style lang="less" scoped> .page { width: 100%; .title { padding-top: 10px; text-align: left; } .clearfix { display: flex; flex-direction: row; align-items: center; width: 100%; .ant-upload-picture-card-wrapper { display: flex; } } .Up { display: flex; .warin { font-family: SourceHanSansSC; font-weight: 400; font-size: 12px; color: rgb(154, 154, 154); font-style: normal; letter-spacing: 0px; line-height: 17px; text-decoration: none; } } .editor-text { border-radius: 3px; font-size: 14px; padding: 0px; text-align: center; background: rgb(239, 239, 239); display: flex; align-items: baseline; flex-direction: column; >p { margin-left: 5px; margin-top: 10px; margin-bottom: 10px; font-weight: 400; font-size: 12px; color: rgb(154, 154, 154); flex: 1; } } } </style>