乐意购项目前端开发 #6

news2024/11/25 20:15:20

一、商品详情页面

 代码模版

创建Detail文件夹, 然后创建index.vue文件

<script setup>
import { getDetail } from "@/api/goods/index";
import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import { useCartStore } from '@/store/cartStore';

const cartStore = useCartStore()
const route = useRoute();
const goods = ref({});
const category = ref({});
const seller = ref({});
const imageList = [
  require(`@/assets/img/hot/hotgoods1.jpg`),
  require(`@/assets/img/hot/hotgoods2.jpg`),
  require(`@/assets/img/hot/hotgoods3.jpg`),
  require(`@/assets/img/hot/hotgoods4.jpg`),
];
// const imageList = []

const getGoods = async () => {
  const res = await getDetail(route.params.id);
  goods.value = res.data.good;
  category.value = res.data.category;
  seller.value = res.data.seller;
  console.log(res.data.pictureList)
  imageList.value = res.data.pictureList
};
//count
const count = ref(1)
const countChange = (count) => {
    console.log(count);
}
//添加购物车
const addCart = () => {
    //console.log(goods)

        cartStore.addCart({
            id: goods.value.id,
            name: goods.value.goodsName,
            picture: goods.value.picture1,
            price: goods.value.price,
            count: count.value,
            // attrsText: skuObj.specsText,
            selected: true
        })
    }


onMounted(() => {
  getGoods();
});
console.log(imageList);
// console.log(data);
</script>


<template>
  <div class="lyg-goods-page">
    <div class="container">
      <div class="bread-container">
        <el-breadcrumb separator=">">
          <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
          <el-breadcrumb-item :to="{ path: `/category/sub/${category.id}` }"
            >{{ category.categoryName }}
          </el-breadcrumb-item>
          <el-breadcrumb-item :to="{ path: '/' }"
            >{{ goods.goodsName }}
          </el-breadcrumb-item>
        </el-breadcrumb>
      </div>
      <!-- 商品信息 -->
      <div class="info-container">
        <div>
          <div class="goods-info">
            <div class="media">
              <!-- 图片预览区 -->
              <!--                 :src="require(`@/assets/img/${goods.picture1}.jpg`)" -->
              <!-- <img class="goods-img" :alt="goods.alt" /> -->
              <LygImageView :image-list="imageList"/>
            </div>
            <div class="spec">
              <!-- 商品信息区 -->
              <p class="g-desc">{{ goods.goodsName }}</p>
              <p class="g-name">{{ goods.goodsDetail }}</p>
              <p class="g-price">
                <span>{{ goods.price }}</span>
                <span> {{ goods.originalPrice }}</span>
              </p>
              <div class="g-service">
                <!-- <dl>
                                    <dt>促销</dt>
                                    <dd>12月好物放送,App领券购买直降120元</dd>
                                </dl> -->
                <dl>
                  <dt>服务</dt>
                  <dd>
                    <span>无忧退货</span>
                    <span>快速退款</span>
                    <span>免费包邮</span>
                    <a href="javascript:;">了解详情</a>
                  </dd>
                </dl>
              </div>
              <!-- 统计数量 -->
              <ul class="goods-sales">
                <li>
                  <p>商品数量</p>
                  <p>{{ goods.goodsNumber }}</p>
                  <p><i class="iconfont icon-comment-filling"></i>查看</p>
                </li>
                <li>
                  <p>人气数值</p>
                  <p>{{ goods.heat }}</p>
                  <p><i class="iconfont icon-task-filling"></i>销量人气</p>
                </li>
                <li>
                  <p>卖家信誉</p>
                  <p>{{ seller.reputation }}</p>
                  <p><i class="iconfont icon-dynamic-filling"></i>卖家主页</p>
                </li>

              </ul>

              <!-- 数据组件 -->
              <el-input-number :min="1" v-model="count" @change="countChange" />
              <!-- 按钮组件 -->
              <div>
                <el-button size="large" class="btn" @click="addCart"> 加入购物车 </el-button>
              </div>
              <!--  -->
            </div>
          </div>

        </div>
      </div>
    </div>
  </div>
</template>


<style scoped lang='scss'>
.lyg-goods-page {
  border-bottom: solid 0.5px #666;
  .goods-info {
    min-height: 600px;
    background: #fff;
    display: flex;

    .media {
      width: 580px;
      height: 600px;
      padding: 30px 100px;
      
    }

    .spec {
      flex: 1;
      padding: 30px 160px 30px 0;
    }
  }

  .goods-footer {
    display: flex;
    margin-top: 20px;

    .goods-article {
      width: 940px;
      margin-right: 20px;
    }

    .goods-aside {
      width: 280px;
      min-height: 1000px;
    }
  }

  .goods-tabs {
    min-height: 600px;
    background: #fff;
  }

  .goods-warn {
    min-height: 600px;
    background: #fff;
    margin-top: 20px;
  }

  .number-box {
    display: flex;
    align-items: center;

    .label {
      width: 60px;
      color: #999;
      padding-left: 10px;
    }
  }

  .g-name {
    width: 520px;
    font-size: 22px;
    text-align: left;
  }

  .g-desc {
    color: #000000;
    font-size: 25px;
    margin-bottom: 10px;
    margin-top: 10px;
  }

  .g-price {
    margin-top: 10px;

    span {
      &::before {
        content: "¥";
        font-size: 14px;
      }

      &:first-child {
        color: $priceColor;
        margin-right: 10px;
        font-size: 22px;
      }

      &:last-child {
        color: #999;
        text-decoration: line-through;
        font-size: 16px;
      }
    }
  }

  .g-service {
    background: #f5f5f5;
    width: 500px;
    padding: 20px 10px 0 10px;
    margin-top: 10px;

    dl {
      padding-bottom: 20px;
      display: flex;
      align-items: center;

      dt {
        width: 50px;
        color: #999;
      }

      dd {
        color: #666;

        &:last-child {
          span {
            margin-right: 10px;

            &::before {
              content: "•";
              color: $lygColor;
              margin-right: 2px;
            }
          }

          a {
            color: $lygColor;
          }
        }
      }
    }
  }

  .goods-sales {
    display: flex;
    width: 400px;
    align-items: center;
    text-align: center;
    height: 140px;

    li {
      flex: 1;
      position: relative;

      ~ li::after {
        position: absolute;
        top: 10px;
        left: 0;
        height: 60px;
        border-left: 1px solid #e4e4e4;
        content: "";
      }

      p {
        &:first-child {
          color: #999;
        }

        &:nth-child(2) {
          color: $priceColor;
          margin-top: 10px;
        }

        &:last-child {
          color: #666;
          margin-top: 10px;

          i {
            color: $lygColor;
            font-size: 14px;
            margin-right: 2px;
          }

          &:hover {
            color: $lygColor;
            cursor: pointer;
          }
        }
      }
    }
  }
}

.goods-tabs {
  min-height: 600px;
  background: #fff;

  nav {
    height: 70px;
    line-height: 70px;
    display: flex;
    border-bottom: 1px solid #f5f5f5;

    a {
      padding: 0 40px;
      font-size: 18px;
      position: relative;

      > span {
        color: $priceColor;
        font-size: 16px;
        margin-left: 10px;
      }
    }
  }
}

.goods-detail {
  padding: 40px;

  .attrs {
    display: flex;
    flex-wrap: wrap;
    margin-bottom: 30px;

    li {
      display: flex;
      margin-bottom: 10px;
      width: 50%;

      .dt {
        width: 100px;
        color: #999;
      }

      .dd {
        flex: 1;
        color: #666;
      }
    }
  }

  > img {
    width: 100%;
  }
}

.btn {
  margin-top: 20px;
}

.bread-container {
  padding: 25px 0;
}
</style>

封装接口

创建文件

import http from "@/utils/http"

//获取商品信息
export function getDetail (id) {
  return http({
    url: '/goods',
      method: 'get',
      params: {
        id
      }
  })
}

配置路由

商品详情页面也是二级页面

{
        path: "/category/new",
        component: () => import("@/views/Category/New.vue"),
      },
      {
        path: "category/sub/:id",
        component: SubCategory,
      },
      {
        path: "/detail/:id",
        component: Detail,
      },
}

链接跳转

将之前页面商品的跳转链接修改

<RouterLink :to="`/detail/${item.id}`">
            
</RouterLink>

二、详情页面图片显示组件

创建文件

index.js在 components 文件夹下, index.vue 在ImgView文件夹下

代码模版

index.vue 

<script setup>
import { ref, watch } from "vue";
import { useMouseInElement } from "@vueuse/core";

//const imageList = [
  // require(`@/assets/img/hot/hotgoods1.jpg`),
  // require(`@/assets/img/hot/hotgoods2.jpg`),
  // require(`@/assets/img/hot/hotgoods3.jpg`),
  // require(`@/assets/img/hot/hotgoods4.jpg`),
//];
const image1List = [
  require(`@/assets/img/hot/hotgoods1.jpg`),
  require(`@/assets/img/hot/hotgoods2.jpg`),
  require(`@/assets/img/hot/hotgoods3.jpg`),
  require(`@/assets/img/hot/hotgoods4.jpg`),
];
// 图片列表
// const imageList = []
const props = defineProps({
    imageList: {
        type: Array,
        default: () => []
    }
})
// const props = defineProps({
//   imageList: Array,
// });
const imgList = props.imageList

//记录激活下标
const activeIndex = ref(0);
//鼠标划过事件
const enterhandler = (i) => {
  activeIndex.value = i;
};

console.log(imgList);
console.log(image1List);
</script>
<!--

 -->
<template>
  <div class="goods-image">
    <!-- 左侧大图-->
    <div class="middle" ref="target">
      <img class="middle-img" :src="imgList[activeIndex]" alt="" />

    </div>
    <!-- 小图列表 -->
    <ul class="small">
      <li
        v-for="(img, i) in imgList"
        :key="i"
        @mouseenter="enterhandler(i)"
        :class="{ active: i === activeIndex }"
      >
        <img :src="img" alt="" />
      </li>
    </ul>


  </div>
</template>

<style scoped lang="scss">
.goods-image {
  width: 480px;
  height: 400px;
  position: relative;
  display: flex;

  .middle {
    width: 400px;
    height: 400px;
    background: #f5f5f5;
    border: solid 1px #f6f6f6;
    .middle-img {
      width: 400px;
      height: 400px;
    }
  }



  .small {
    width: 80px;

    li {
      width: 68px;
      height: 68px;
      margin-left: 12px;
      margin-bottom: 15px;
      border: solid 1px #dad6d6;
      cursor: pointer;
      img {
        width: 68px;
        height: 68px;
      }

      &:hover,
      &.active {
        border: 2px solid $lygColor;
      }
    }
  }
}
</style>

 index.js

// 通过插件的方式把components中的所有组件都进行全局化注册
import ImageView from './ImageView/index.vue'
export const componentPlugin ={
    install(app){
        // app.component('组件名字',组件配置对象)
        app.component('LygImageView',ImageView)
    }
}

三、登录页面

代码模版

创建文件

<script setup>
import {useUserStore} from '@/store/user'
import { ref } from "vue";
import { useRouter } from 'vue-router';

// 1.准备表单对象
const form = ref({
  username: "",
  password: "",
  agree: true,
});
// 2. 校验规则对象
const rules = {
  username: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
  password: [
    { required: true, message: "密码不能为空", trigger: "blur" },
    { min: 6, max: 24, message: "密码长度要求6-14个字符", trigger: "blur" },
  ],
  agree: [
    {
      validator: (rule, value, callBack) => {
        console.log(value);
        //自定义校验逻辑
        // 勾选协议通过,不勾选不通过
        if (value) {
          callBack();
        } else {
          callBack(new Error("请勾选协议"));
        }
      },
    },
  ],
};
// 3.获取 form 实例做统一校验
const router = useRouter()
const formRef = ref(null)
const userStore =  useUserStore()
const doLogin = () => {
  const { username, password } = form.value
  // 调用实例方法
  formRef.value.validate(async (valid) => {
    // valid: 所有表单都通过校验  才为true
    console.log(valid)
    console.log(username,password)
    // 以valid做为判断条件 如果通过校验才执行登录逻辑
    if (valid) {

      // TODO LOGIN
      await userStore.getUserInfo({ username, password })

      // 1. 提示用户
      ElMessage({ type: 'success', message: '登录成功' })
      // 2. 跳转首页
      router.replace({ path: '/' })
    }
  })
}
// TODO LOGIN



</script>

<template>
  <div class="wrap">
    <header class="login-header">
      <div class="container m-top-20">
        <h1 class="logo">
          <a href="/">乐易购</a>
        </h1>
        <RouterLink class="entry" to="/">
          进入网站首页
          <i class="iconfont icon-angle-right"></i>
          <i class="iconfont icon-angle-right"></i>
        </RouterLink>
      </div>
    </header>
    <section class="login-section">
      <div class="wrapper">
        <nav>
          <a href="javascript:;">账户登录</a>
        </nav>
        <div class="username-box">
          <div class="form">
            <el-form ref="formRef" label-position="right" :model="form"
             :rules="rules"
              label-width="60px" status-icon>
              <el-form-item prop="username" label="账户">
                <el-input v-model="form.username" />
              </el-form-item>
              <el-form-item prop="password" label="密码">
                <el-input v-model="form.password" />
              </el-form-item>
              <el-form-item prop="agree" label-width="22px">
                <el-checkbox size="large" v-model="form.agree">
                  我已同意隐私条款和服务条款
                </el-checkbox>
              </el-form-item>

              <el-button size="large" class="subBtn" @click="doLogin">点击登录</el-button>
            </el-form>
          </div>
        </div>
      </div>
    </section>

    <footer class="login-footer">
      <div class="container">
        <p>
          <a href="javascript:;">关于我们</a>
          <a href="javascript:;">帮助中心</a>
          <a href="javascript:;">售后服务</a>
          <a href="javascript:;">配送与验收</a>
          <a href="javascript:;">商务合作</a>
          <a href="javascript:;">搜索推荐</a>
          <a href="javascript:;">友情链接</a>
        </p>
        <p>CopyRight &copy; 乐易购</p>
      </div>
    </footer>
  </div>
</template>

<style scoped lang='scss'>

.login-header {
  background: #fff;
  border-bottom: 1px solid #e4e4e4;

  .container {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
  }

  .logo {
    width: 300px;
    height: 132px;
    text-align: right;
    line-height: 132px;
    text-shadow: 5px 5px 2px #251818;
    font-size: 45px;
    letter-spacing: 0.2em;
    font-family: Microsoft YaHei;
    a {
      height: 132px;
      width: 100%;
      text-indent: -9999px;
      color: $lygColor;
    }
  }

  .sub {
    flex: 1;
    font-size: 24px;
    font-weight: normal;
    margin-bottom: 38px;
    margin-left: 20px;
    color: #666;
  }

  .entry {
    color: #000;
    width: 120px;
    margin-bottom: 38px;
    font-size: 16px;

    i {
      font-size: 14px;
      color: $warnColor;
      letter-spacing: -5px;
    }
  }
}

.login-section {
  background: url('@/assets/login.png')  no-repeat center / cover;
  height: 488px;
  position: relative;

  .wrapper {

    width: 380px;
    background: #fff;
    position: absolute;
    left: 50%;
    top: 54px;
    transform: translate3d(100px, 0, 0);
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.15);

    nav {
      font-size: 14px;
      height: 55px;
      margin-bottom: 20px;
      border-bottom: 1px solid #f5f5f5;
      display: flex;
      padding: 0 40px;
      text-align: right;
      align-items: center;

      a {
        color: #000;
        flex: 1;
        line-height: 1;
        display: inline-block;
        font-size: 18px;
        position: relative;
        text-align: center;
      }
    }
  }
}

.login-footer {
  padding: 30px 0 50px;
  background: #fff;

  p {
    text-align: center;
    color: #999;
    padding-top: 20px;

    a {
      line-height: 1;
      padding: 0 10px;
      color: #999;
      display: inline-block;

      ~ a {
        border-left: 1px solid #ccc;
      }
    }
  }
}

.username-box {
  .toggle {
    padding: 15px 40px;
    text-align: right;

    a {
      color: $lygColor;

      i {
        font-size: 14px;
      }
    }
  }

  .form {
    padding: 0 20px 20px 20px;

    &-item {
      margin-bottom: 28px;

      .input {
        position: relative;
        height: 36px;

        > i {
          width: 34px;
          height: 34px;
          background: #cfcdcd;
          color: #fff;
          position: absolute;
          left: 1px;
          top: 1px;
          text-align: center;
          line-height: 34px;
          font-size: 18px;
        }

        input {
          padding-left: 44px;
          border: 1px solid #cfcdcd;
          height: 36px;
          line-height: 36px;
          width: 100%;

          &.error {
            border-color: $priceColor;
          }

          &.active,
          &:focus {
            border-color: $lygColor;
          }
        }

        .code {
          position: absolute;
          right: 1px;
          top: 1px;
          text-align: center;
          line-height: 34px;
          font-size: 14px;
          background: #f5f5f5;
          color: #666;
          width: 90px;
          height: 34px;
          cursor: pointer;
        }
      }

      > .error {
        position: absolute;
        font-size: 12px;
        line-height: 28px;
        color: $priceColor;

        i {
          font-size: 14px;
          margin-right: 2px;
        }
      }
    }

    .agree {
      a {
        color: #069;
      }
    }

    .btn {
      display: block;
      width: 100%;
      height: 40px;
      color: #fff;
      text-align: center;
      line-height: 40px;
      background: $lygColor;

      &.disabled {
        background: #cfcdcd;
      }
    }
  }

  .action {
    padding: 20px 40px;
    display: flex;
    justify-content: space-between;
    align-items: center;

    .url {
      a {
        color: #999;
        margin-left: 10px;
      }
    }
  }
}

.subBtn {
  background: $lygColor;
  width: 100%;
  color: #fff;
}
</style>

封装接口

创建文件

编写代码("username" , "password" 要和你数据库的属性对应上)

import http from '@/utils/http'

export function loginAPI ({ username,password}) {
  return http({
    url: '/login',
    method: 'POST',
    data:{
      "username": username,
      "password": password
    },
  })
}

配置路由

登录页面是一级页面

const routes = [
  {
    // Home 页面是首页下的二级页面,所以要配置在首页路径下
    path: "/",
    component: Layout,
    children: [
      ...//省略
  },
  {
    path: "/login",
    component: Login,
  },
];

用户数据持久化

要先安装pinia

安装pinia持久化插件 pinia-plugin-persistedstate

npm i pinia-plugin-persistedstate  

在main.js中注册插件

import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPersist)
const app = createApp(App)

app.use(pinia)

创建文件

// 管理用户数据相关
import { defineStore } from "pinia";
import { ref } from "vue";
import { loginAPI } from "@/api/login/index";
import { useCartStore } from "./cartStore";

export const useUserStore = defineStore(
  "user",
  () => {
    const cartStore = useCartStore();
    // 1. 定义管理用户数据的state
    const userInfo = ref({});
    // 2. 定义获取接口数据的action函数
    const getUserInfo = async ({ username, password }) => {
      const res = await loginAPI({ username, password });
      //console.log(res.data.code)
      // console.log(res.data.token)
      userInfo.value = res.data;

      //window.sessionStorage.setItem('token', res.data.token);
      
      //获取最新的购物车列表
      cartStore.updateNewList();
    };
    // 退出时清除用户信息
    const clearUserInfo = () => {
      userInfo.value = {};
      //window.sessionStorage.clear;
      //执行清除购物车的action
      cartStore.clearCart;
    };
    // 3. 以对象的格式把state和action return
    return {
      userInfo,
      getUserInfo,
      clearUserInfo,
    };
  },
  {
    persist: true,
  }
);

修改LayoutNav.vue

获取pinia中的用户数据

import { useUserStore } from '@/store/user'

const userStore = useUserStore()

 根据是否登录状态来显示

<template v-if="userStore.userInfo.token">
                    <li><a href="javascript:;" @click="$router.push('/my')"><i class=" iconfont icon-user"></i>{{ userStore.userInfo.user.username }}</a></li>
                    <li>
                        <el-popconfirm @confirm="confirm" title="确认退出吗?"  cancel-button-text="取消" confirm-button-text="确认">
                            <template #reference>
                                <a href="javascript:;">退出登录</a>
                            </template>
                        </el-popconfirm>
                    </li>
                    <li><a href="javascript:;">我的订单</a></li>
                </template>
                <template v-else>
                  <li><a href="javascript:;" @click="router.push('/login')">请先登录</a></li>
                    <li><a href="javascript:;">帮助中心</a></li>
                    <li><a href="javascript:;">关于我们</a></li>
                </template>

 整体代码

<script setup>
import { useUserStore } from '@/store/user'
import { useRouter } from 'vue-router'

const userStore = useUserStore()
const router = useRouter()
const confirm = () => {
  console.log('用户要退出登录了')
  // 退出登录业务逻辑实现
  // 1.清除用户信息 触发action
  userStore.clearUserInfo()
  // 2.跳转到登录页
  router.push('/login')
}
console.log(userStore)
</script>


<template>
    <nav class="app-topnav">
        <div class="container">
            <ul>
              <template v-if="userStore.userInfo.token">
                    <li><a href="javascript:;" @click="$router.push('/my')"><i class=" iconfont icon-user"></i>{{ userStore.userInfo.user.username }}</a></li>
                    <li>
                        <el-popconfirm @confirm="confirm" title="确认退出吗?"  cancel-button-text="取消" confirm-button-text="确认">
                            <template #reference>
                                <a href="javascript:;">退出登录</a>
                            </template>
                        </el-popconfirm>
                    </li>
                    <li><a href="javascript:;">我的订单</a></li>
                </template>
                <template v-else>
                  <li><a href="javascript:;" @click="router.push('/login')">请先登录</a></li>
                    <li><a href="javascript:;">帮助中心</a></li>
                    <li><a href="javascript:;">关于我们</a></li>
                </template>
            </ul>
        </div>
    </nav>
</template>


<style scoped lang="scss">
.app-topnav {
    background: #333;

    ul {
        display: flex;
        height: 53px;
        justify-content: flex-end;
        align-items: center;

        li {
            a {
                padding: 0 15px;
                color: #cdcdcd;
                line-height: 1;
                display: inline-block;

                i {
                    font-size: 14px;
                    margin-right: 2px;
                }

                &:hover {
                    color: $lygColor;
                }
            }

            ~li {
                a {
                    border-left: 2px solid #666;
                }
            }
        }
    }
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1433627.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手写分布式存储系统v0.3版本

引言 承接 手写分布式存储系统v0.2版本 &#xff0c;今天开始新的迭代开发。主要实现 服务发现功能 一、什么是服务发现 由于咱们的服务是分布式的&#xff0c;那从服务管理的角度来看肯定是要有一个机制来知道具体都有哪些实例可以提供服务。举个例子就是&#xff0c;张三家…

《大魔界村》中的人物性格——亚瑟

《大魔界村》作为一款经典的街机动作游戏,其主角——勇敢的骑士亚瑟,以其独特的性格特点和坚定的信念,在玩家心中留下了深刻印象。本文将深入探讨亚瑟这一角色的性格特质,通过分析他在游戏中的行为表现及决策过程,展现他身上的勇气、坚韧与智慧三大要点。 一、无畏挑战的…

全套电气自动化样例图纸分享,使用SuperWorks自动化版免费设计软件!

今天给大家分享一套完备的电气自动化样例图纸&#xff0c;结构准确、内容清晰&#xff0c;适合初学者入门操作练习。 整套图纸包含图纸目录、原理图、端子列表、连接列表、元件列表、接线图&#xff0c;具有较高的参考价值&#xff0c;请大家点击自行下载文件&#xff01; 1e8…

【51单片机】直流电机实验和步进电机实验

目录 直流电机实验直流电机介绍ULN2003 芯片介绍硬件设计软件设计实验现象 步进电机实验步进电机简介步进电机的工作原理步进电机极性区分双极性步进电机驱动原理单极性步进电机驱动原理细分驱动原理 28BYJ-48 步进电机简介软件设计 橙色 直流电机实验 在未学习 PWM 之前&…

出海企业应用CRM系统可行吗?有哪些好处?

近年来许多企业都涌现出了出海需求&#xff0c;在不同国家设置了办事处。企业在管理业务和客户时&#xff0c;不可避免用到CRM管理系统。对于这样的跨国企业&#xff0c;是否有一个CRM系统可以满足其需求&#xff1f;——答案是有的&#xff0c;这篇文章将为您介绍跨国协作CRM的…

Palworld幻兽帕鲁自建服务器32人联机开黑!

玩转幻兽帕鲁服务器&#xff0c;阿里云推出新手0基础一键部署幻兽帕鲁服务器教程&#xff0c;傻瓜式一键部署&#xff0c;3分钟即可成功创建一台Palworld专属服务器&#xff0c;成本仅需26元&#xff0c;阿里云服务器网aliyunfuwuqi.com分享2024年新版基于阿里云搭建幻兽帕鲁服…

Java实现康复中心管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 普通用户模块2.2 护工模块2.3 管理员模块 三、系统展示四、核心代码4.1 查询康复护理4.2 新增康复训练4.3 查询房间4.4 查询来访4.5 新增用药 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的康复中…

vue项目中的 package.json 的文件是什么

在 Vue.js 项目中&#xff0c;package.json 文件是一个 JSON 文件&#xff0c;用于存储项目的元数据和依赖关系。这个文件应该位于项目的根目录下。 以下是一个简单的 package.json 文件示例&#xff1a; {"name": "my-vue-project","version"…

MySQL进阶45讲【10】MySQL为什么有时候会选错索引?

1 前言 前面我们介绍过索引&#xff0c;在MySQL中一张表其实是可以支持多个索引的。但是&#xff0c;写SQL语句的时候&#xff0c;并没有主动指定使用哪个索引。也就是说&#xff0c;使用哪个索引是由MySQL来确定的。 大家有没有碰到过这种情况&#xff0c;一条本来可以执行得…

【爬虫实战】全过程详细讲解如何使用python获取抖音评论,包括二级评论

简介&#xff1a; 前两天&#xff0c;TaoTao发布了一篇关于“获取抖音评论”的文章。但是之前的那一篇包涵的代码呢仅仅只能获取一级评论。虽然说抖音的一级评论挺精彩的了&#xff0c;但是其实二级评论更加有意思&#xff0c;同时二级评论的数量是很多。所以二级评论是非常值…

springboot整合rabbitmq,及各类型交换机详解

RabbitMQ交换机&#xff1a; 一.交换机的作用 如果直接发送信息给一条队列&#xff0c;而这一消息需要多个队列的的多个消费者共同执行&#xff0c;可此时只会有一个队列的一个消费者接收该消息并处理&#xff0c;其他队列的消费者无法获取消息并执行。所以此时就需要交换机接…

c++ 语法多态

多态分为两类 静态多态&#xff1a;函数重载和运算符重载属于静态多态复用函数名 动态多态&#xff1a; 派生类和虚函数实现运行时多态。 静态多态和动态多态区别 静态多态的函数地址早绑定&#xff1a;编译阶段确定函数地址 动态多态函数地址晚绑定&#xff1a;运行阶段确…

esp8266 步骤

安装驱动 http://arduino.esp8266.com/stable/package_esp8266com_index.json oled库 esp8266-oled-ssd1306

01-Datahub是什么?

Datahub是LinkedIn开源的基于现代数据栈的元数据管理平台&#xff0c;原来叫做WhereHows 。经过一段时间的发展datahub于2020年2月在Github开源。 官网地址为&#xff1a;A Metadata Platform for the Modern Data Stack | DataHub 源码地址为&#xff1a;GitHub - datahub-p…

飞天使-k8s知识点12-kubernetes散装知识点1-架构有状态

文章目录 k8s架构图有状态和无状态服务 资源和对象对象规约和状态 资源的对象-资源的分类 k8s架构图 有状态和无状态服务 区分有状态和无状态服务有利于维护yaml文件 因为配置不同资源和对象 命令行yaml来定义对象对象规约和状态 规约 spec 描述对象的期望状态状态 status 对…

ArcGIS学习(三)数据可视化

ArcGIS学习(三)数据可视化 1.矢量数据可视化 需要提前说明的是,在ArcGIS中,所有的可视化选项设置都是在“图层属性”对话框里面的“符号系统”中实现的。 对于矢量数据的可视化,主要有四种可视化方式: 按“要素”可视化按“类别”可视化按“数量”可视化按“图表”可视…

【证书管理】实验报告

证书管理实验 【实验环境】 ISES客户端 【实验步骤】 查看证书 查看证书详细信息 选择任意证书状态&#xff0c;在下方“证书列表”中出现符合要求的所有证书。在“证书列表”中点击要查看证书&#xff0c;在右侧“证书详细信息”栏出现被选证书信息。 上述操作如图1.2.…

PS一键磨皮插件Delicious Retouch for mac中文 支持PS2024

Delicious Retouch for Mac是一款优秀的Photoshop插件&#xff0c;专注于人像修饰。以下是该插件的一些主要特点和功能&#xff1a; 软件下载&#xff1a;Delicious Retouch for mac中文 支持PS2024 人像修饰工具&#xff1a;Delicious Retouch专注于人像修饰&#xff0c;提供了…

编程实例分享,物流车辆调度管理系统软件教程

编程实例分享&#xff0c;物流车辆调度管理系统软件教程 一、前言 以下教程以 佳易王物流车辆调度管理系统软件V16.0为例说明 如上图&#xff0c;左侧为 导航栏&#xff0c;在系统设置里可以设置打印参数 如上图&#xff0c;填写托运方&#xff0c;货物&#xff0c;司机等信…

idea 快捷键ctrl+shift+f失效的解决方案

文章目录 搜狗输入法快捷键冲突微软输入法快捷键冲突 idea的快捷键ctrlshiftf按了没反应&#xff0c;理论上是快捷键冲突了&#xff0c;检查搜狗输入法和微软输入法快捷键。 搜狗输入法快捷键冲突 不需要简繁切换的快捷键&#xff0c;可以关闭它&#xff0c;或修改快捷键。 微…