| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- <script >
- import langMap from "@/map/langMap";
- import {unescapeHtml} from "@/until/unescapeHtml";
- import {timestampToTime} from "@/until/time";
- // 导入ant-design-vue的组件
- import {Tabs, Tag} from 'ant-design-vue'
- // 引入样式, 这里使用单独抽离出来的antd样式
- import '@/assets/antd_tabs.css'
- import imageViewer from "@/components/public/imageViewer.vue";
- /**
- * emit 事件
- * tryBuy 用户尝试购买
- */
- export default {
- name: "productInfo",
- components: {
- ATabs: Tabs,
- ATabPane: Tabs.TabPane,
- ATag: Tag,
- imageViewer
- },
- props: {
- productId: {
- type: Number,
- },
- lang: {
- type: String,
- default: langMap.lang.zh
- },
- unescape: {
- type: Boolean,
- default: true
- },
- product: {
- type: Object,
- default: () => {
- return {}
- }
- }
- },
- data() {
- return {
- loading: false,
- showImage: '',
- productInfo: {
- }
- }
- },
- watch: {
- // 监听product变化
- product(newVal, oldVal) {
- this.productInfoChange();
- }
- },
- beforeMount() {
- this.productInfoChange();
- },
- mounted() {
- this.$forceUpdate()
- },
- methods: {
- productInfoChange(){
- let data = this.product;
- if(this.unescape){
- data.detail = unescapeHtml(data.detail);
- data.overview = unescapeHtml(data.overview);
- data.parameter = unescapeHtml(data.parameter);
- }
- data.add_time = timestampToTime(data.add_time);
- console.log(data)
- this.$nextTick(()=>{
- this.showImage = data.image;
- //this.$forceUpdate()
- })
- // 将产品主图添加至第一个子图中
- if( data.sub_images){
- console.log(data.image)
- data.sub_images.unshift(data.image);
- }
- this.productInfo = data;
- },
- parseTags(tagArrStr){
- console.log(tagArrStr)
- let tags = tagArrStr
- if (!tags) {
- return [];
- }
- // 去除空字符串
- tags = tags.replace(/\s/g,'')
- let tagArr = tags.split(',')
- // 标签去重
- tagArr = [...new Set(tagArr)]
- // 移除空标签
- tagArr = tagArr.filter(item => item)
- return tagArr
- },
- getLangText(str) {
- return langMap.getText(this.lang, str);
- },
- /**
- * 图片路径处理, 兼容手动上传的图片与后期自动增加的图片
- * @param text
- * @return {*|string|string}
- */
- imagePathBabel(text){
- let result = text?text.charAt(0) == '/'? text : '/public/'+text : ''
- return result
- },
- changeShowImages(nextIndex){
- let ul = this.$refs.imageList;
- let ulWidth = ul.offsetWidth;
- let parentWidth = ul.parentElement.offsetWidth;
- let nextImage = this.productInfo.sub_images[nextIndex]
- // 计算 top偏移值
- let left = 0;
- left = nextIndex * 100 + (10 * nextIndex);
- // 偏移位置锁定
- if (ulWidth - parentWidth < left) {
- left = ulWidth - parentWidth;
- }
- if (left < 0) {
- left = 0;
- }
- // 移动图片组件
- ul.style.left = `-${left}px`
- this.showImage = nextImage
- },
- tryBuy(){
- this.$emit('tryBuy')
- }
- }
- }
- </script>
- <template>
- <div class="product_view">
- <div class="grid product">
- <div class="product_image">
- <div class="product-image">
- <img class="active"
- :src="imagePathBabel(showImage)" ></img>
- </div>
- <div class="sub_images">
- <div class="con-btn prev">
- <svg-icon icon-class="prev" />
- </div>
- <ul class="image-list" ref="imageList" >
- <li class="image-item"
- v-for="(subImage, index) in productInfo.sub_images"
- :key="`${productInfo.proid}-sub-${index}-${subImage}`"
- @click="changeShowImages(index)"
- >
- <img :src="imagePathBabel(subImage)">
- </li>
- </ul>
- <div class="con-btn next">
- <svg-icon icon-class="next" />
- </div>
- </div>
- </div>
- <div class="product_brief">
- <h1>{{ productInfo.name }}</h1>
- <div class="tags">
- <a-tag
- v-for="tag in parseTags(productInfo.seo_key)"
- :key="tag"
- color="#2db7f5"
- >
- {{ tag }}
- </a-tag>
- </div>
- <div class="description" v-html="productInfo.overview">
- </div>
- <button class="add-to-cart" @click="tryBuy">{{ getLangText("联系购买") }}</button>
- </div>
- </div>
- <div class="product_detail">
- <!-- 产品介绍-->
- <!-- 产品详情-->
- <a-tabs default-active-key="detail" >
- <a-tab-pane key="detail" :tab="getLangText(`介绍`)">
- <div class="description" v-html="productInfo.detail">
- </div>
- </a-tab-pane>
- <a-tab-pane key="parameter" :tab="getLangText(`参数`)">
- <div class="description" v-html="productInfo.parameter">
- </div>
- </a-tab-pane>
- </a-tabs>
- </div>
- </div>
- </template>
- <style scoped>
- h1{
- font-size: 2.5rem;
- }
- .product_view{
- width: 100%;
- height: 100%;
- padding: 0.5rem;
- position: relative;
- }
- .product{
- width: 100%;
- height: auto;
- display: flex;
- flex-wrap: wrap;
- }
- .product .product_image{
- width: 40%;
- height: auto;
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 1rem;
- box-sizing: border-box;
- }
- .product .product_brief{
- width: calc(60% - 10px);
- height: auto;
- min-height: 510px;
- padding: 5px 10px;
- box-sizing: border-box;
- border-left: 1px solid #e3dddd;
- }
- .product_image .product-image{
- width: calc(100% - 5px);
- min-width: 200px;
- max-width: 400px;
- height: auto;
- }
- .product_image .product-image img{
- animation: fadeImg 1s;
- width: 100%;
- height: auto;
- }
- .product_image .sub_images{
- width: 100%;
- height: 110px;
- padding: 5px 0;
- box-sizing: border-box;
- display: flex;
- position: relative;
- overflow: hidden;
- }
- .product_image .sub_images .con-btn{
- width: 30px;
- height: calc(100% - 10px);
- position: absolute;
- top: 5px;
- display: flex;
- justify-content: center;
- align-items: center;
- cursor: pointer;
- }
- .product_image .sub_images .con-btn:hover{
- background-color: rgba(0,0,0,0.1);
- }
- .sub_images .prev{
- left: 0;
- }
- .sub_images .next{
- right: 0;
- }
- .sub_images .image-list{
- width: auto;
- height: 100px;
- display: flex;
- position: absolute;
- top: 0;
- }
- .sub_images .image-list .image-item{
- width: 100px;
- margin-right: 10px;
- height: 100%;
- }
- .sub_images .image-list .image-item img{
- object-fit: cover;
- width: 100%;
- height: 100%;
- }
- .tags{
- width: 100%;
- display: flex;
- flex-wrap: wrap;
- justify-content: flex-start;
- align-items: center;
- padding: 5px;
- box-sizing: border-box;
- }
- .description {
- padding: 1rem;
- }
- .add-to-cart{
- position: relative;
- display: inline-block;
- background: #3e3e3f;
- color: #fff;
- border: none;
- border-radius: 0;
- padding: 1rem 2.5rem;
- font-size: 1rem;
- text-transform: uppercase;
- cursor: pointer;
- transform: translateZ(0);
- transition: color 0.3s ease;
- letter-spacing: 0.0625rem;
- }
- .add-to-cart:hover::before {
- transform: scaleX(1);
- }
- .add-to-cart::before {
- position: absolute;
- content: "";
- z-index: -1;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: #565657;
- transform: scaleX(0);
- transform-origin: 0 50%;
- transition: transform 0.3s ease-out;
- }
- @keyframes fadeImg {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
- }
- </style>
- <style>
- /** table style */
- .table {
- background: white;
- border-radius:3px;
- border-collapse: collapse;
- padding:5px;
- width: auto;
- box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
- animation: float 5s infinite;
- }
- th {
- color:#D5DDE5;;
- background:#1b1e24;
- border-bottom:4px solid #9ea7af;
- border-right: 1px solid #343a45;
- font-size:23px;
- font-weight: 100;
- padding:24px;
- text-align:left;
- text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
- vertical-align:middle;
- }
- th:first-child {
- border-top-left-radius:3px;
- }
- th:last-child {
- border-top-right-radius:3px;
- border-right:none;
- }
- tr {
- border-top: 1px solid #C1C3D1;
- border-bottom-: 1px solid #C1C3D1;
- color:#666B85;
- font-size:16px;
- font-weight:normal;
- text-shadow: 0 1px 1px rgba(256, 256, 256, 0.1);
- }
- tr:hover td {
- background:#4E5066;
- color:#FFFFFF;
- border-top: 1px solid #22262e;
- }
- tr:first-child {
- border-top:none;
- }
- tr:last-child {
- border-bottom:none;
- }
- tr:nth-child(odd) td {
- background:#EBEBEB;
- }
- tr:nth-child(odd):hover td {
- background:#4E5066;
- }
- tr:last-child td:first-child {
- border-bottom-left-radius:3px;
- }
- tr:last-child td:last-child {
- border-bottom-right-radius:3px;
- }
- td {
- background:#FFFFFF;
- padding:20px;
- text-align:left;
- vertical-align:middle;
- font-weight:300;
- font-size:18px;
- text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.1);
- border-right: 1px solid #C1C3D1;
- }
- td:last-child {
- border-right: 0px;
- }
- th.text-left {
- text-align: left;
- }
- th.text-center {
- text-align: center;
- }
- th.text-right {
- text-align: right;
- }
- td.text-left {
- text-align: left;
- }
- td.text-center {
- text-align: center;
- }
- td.text-right {
- text-align: right;
- }
- </style>
|