“惠医通-医院挂号订单平台”

在这里插入图片描述

结合已学习过的vue3和TS完成的项目,便于患者对自己想要就诊的科室进行挂号,付款

一:项目简介

前端技术栈

Vue3

TS

vue-router

Element-ui

Axios

Pinia

项目架构

image-20230828170348965

二:主要模块

1. axios二次封装

1.1 创建实例

//利用axios.create方法创建一个axios实例
const request = axios.create({
    baseURL: '/api', //请求基础路径设置
    timeout: 5000 //超时的时间设置,超出5s请求就是失败
})

1.2 请求拦截器

引入store仓库中的用户token,设置请求头携带token参数,后序请求需要验证token

//请求拦截器
request.interceptors.request.use(config => {
    //config:请求拦截器回调注入的对象(配置对象),配置对象的身上最重要的一件事情headers属性
    //可以通过请求头携带公共参数 -token
    //获取用户仓库
    let userStore = useUserStore()
    // console.log(userStore.userInfo)
    // token: 公共参数,用户登录了需要携带
    if (userStore.userInfo.token) {
        config.headers.token = userStore.userInfo.token
    }

    return config
})

1.3 响应拦截器

利用响应拦截器进行简化数据

当http网络错误时,设置提示信息

//响应拦截器
request.interceptors.response.use(
    response => {
        //响应拦截器成功的回调,一般会简化数据
        return response.data
    },
    error => {
        //处理http网络错误
        let status = error.response.status
        switch (status) {
            case 404:
                //错误信息
                ElMessage({
                    type: 'error',
                    message: '请求失败路径出现问题'
                })
                break
            case 500 | 501 | 502 | 503 | 504 | 505:
                //错误信息
                ElMessage({
                    type: 'error',
                    message: '服务器错误'
                })
                break
            case 401:
                //错误信息
                ElMessage({
                    type: 'error',
                    message: '参数有误'
                })
                break
        }
        return Promise.reject(new Error(error.message))
    }
)

2. vite配置代理跨域

在跨域请求时,浏览器会采取同源策略来限制来自不同源的跨域请求,为了解决这个问题,通常可以采用代理服务器来处理该问题,使得请求在同源的环境下进行

vite服务器会将请求转发到指定的代理服务器,代理服务器再向目标请求地址发起请求

代理服务器接收到真正的响应后,再将其返回给vite服务器,最终返回给前端

    //配置代理跨域
    server: {
        proxy: {
            '/api': {
                target: 'http:xxx.cn',
                changeOrigin: true
            }
        }
    }

3. 首页: 搜索栏

image-20230828172454394

element-ui组件-自动补全输入框

        <el-autocomplete
            @select="goDetail"
            :trigger-on-focus="false"
            clearable
            placeholder="请你输入医院名称"
            v-model="hosname"
            :fetch-suggestions="fetchData"
        />
//引入请求方法
import { reqHospitalInfo } from '@/api/home'
import type { HospitalInfo } from '@/api/home/type'
//创建路由器对象
let $router = useRouter()
//收集搜索的关键字(医院的名字)
let hosname = ref<string>('')

//顶部组件的回调
const fetchData = async (keyword: string, cb: any) => {
    //当用户输入完关键字时 函数执行 发送请求获取需要展示的数据
    // console.log(123)
    let result: HospitalInfo = await reqHospitalInfo(keyword)
    // console.log(result)
    //该组件 需要的数据字段为 value 返回的数据字段为hosname 整理修改
    let showData = result.data.map(item => {
        return {
            value: item.hosname, //展示的是医院的编码
            hoscode: item.hoscode //存储医院的编码
        }
    })
    //给组件提供展示的数据
    cb(showData)
}

//点击某一个推荐项
const goDetail = (item: any) => {
    //点击推荐项目进入医院详情页,将来需要携带query参数(医院的编码)
    // console.log(item)

    $router.push({ path: '/hospital/register', query: { hoscode: item.hoscode } })
}

image-20230828172926766

  • fetch-suggestions方法,需要两个参数,keyword是搜索框输入的参数,cb,callback回调函数,需要将给组件展示的数据传给回调函数
  • 因此,调用根据输入的字段获取医院信息,使用map方法遍历返回的数据,再根据对应的字段将数据返回出来,作为showData,再将其传入回调

image-20230828173723770

  • select事件,当选中对应选项时触发,携带对应医院参数跳转到对应医院详情页

4. 首页: 根据等级和地区筛选

image-20230828174031670

4.1 子组件:Level-医院等级

  • 自定义事件向父组件传递等级参数

  • 子组件通过defineEmits设置要发射给父组件需要使用的方法getLevel

  • 使用defineEmits会返回一个方法,使用一个变量emits(变量名随意)去接收

  • 在对应时机触发事件,并传入需要传递给父组件的参数

    //点击等级的按钮回调
    const changeLevel = (level: string) => {
        //高亮响应式数据存储leve数值
        activeFlag.value = level
        //触发自定义事件: 将医院的等级数值传递给父组件
        $emit('getLevel', level)
    }
    
    let $emit = defineEmits(['getLevel'])
    

4.2 子组件:Region-地区

//点击不同区域按钮回调
const changeRegion = (region: string) => {
    regionFlag.value = region
    //触发自定义事件传值
    $emits('getRegion', region)
}

let $emits = defineEmits(['getRegion'])

4.3 父组件:home-首页

  • 当页面挂载时候,获取医院数据并展示
  • 但当用户选中等级和地区时,需要重新根据对应的参数获取对应的医院数据
  • 因此需要用到地区子组件和等级子组件传递来的对应参数
  • 用到自定义事件接受两个子组件传递的参数
//子组件自定义事件:获取子组件传递的医院等级数据
const getLevel = (level: string) => {
    //更新存储医院等级数据
    hosType.value = level
    //更新完医院等级数据再重新发起请求
    getHospitalInfo()
}
//子组件自定义事件:获取子组件传递的地区数据
const getRegion = (region: string) => {
    //更新存储医院地区数据
    districtCode.value = region
    //更新完医院等级数据再重新发起请求
    getHospitalInfo()
}

5. 登录/退出

image-20230828180304420

//用户登录
const login = async () => {
    //保证表单校验两项都复合条件
    await form.value.validate()
    try {
        //用户登录成功
        await userStore.userLogin(loginParam)
        //关闭对话框
        userStore.visiable = false
        //获取url的query参数
        let redirect = $route.query.redirect
        if (redirect) {
            $router.push(redirect as string)
        } else {
            $router.push('/home')
        }
    } catch (error) {
        ElMessage({
            type: 'error',
            message: (error as Error).message
        })
    }
}
  • 仓库处理登录逻辑,并保存响应状态
        //用户登录请求
        async userLogin(loginParam: any) {
            let result: UserLoginResponseData = await reqUserLogin(loginParam)
            // console.log(loginParam)
            // console.log(result)
            if (result.code === 200) {
                //存储name和token
                this.userInfo = result.data
                //本地存储持久化存储用户信息
                SET_TOKEN(JSON.stringify(this.userInfo))
                return 'ok'
            } else {
                return Promise.reject(new Error(result.message))
            }
        },
//本地存储操作用户信息的方法
export const SET_TOKEN = (userInfo: string) => {
    localStorage.setItem('userInfo', userInfo)
}

export const GET_TOKEN = () => {
    return localStorage.getItem('userInfo')
}

export const REMOVE_TOKEN = () => {
    localStorage.removeItem('userInfo')
}

  • 封装操作用户相关信息持久化存储的相关方法

image-20230828181203029

        //退出登录
        loginOut() {
            //清空仓库的数据
            this.userInfo = { name: '', token: '' }
            //清空本地存储的数据
            REMOVE_TOKEN()
        }
  • 退出登录,清空仓库的数据,清除本地存储数据

6. 挂号

image-20230828181346006

//点击对应日期获取对应数据存储
const changeTime = async (item: string) => {
    workTime.value = item
    //再调用获取医生数据请求
    getDoctorWorkData()
}
//获取当前日期下的医生信息和票价格请求
const getDoctorWorkData = async () => {
    //三个参数
    //医院编号
    let hoscode: string = $route.query.hoscode as string
    //科室编号
    let depcode: string = $route.query.depcode as string
    //工作日期
    let workDate: string = workTime.value.workDate
    //发请求存储数据
    let result: DoctorResponseData = await reqHospitalDoctor(hoscode, depcode, workDate)
    // console.log(result)
    if (result.code === 200) {
        docArr.value = result.data
    }
}
  • workTime存储改日日期,通过点击对应日期,更新workTime的值,然后再次获取医生数据请求,就可以获取选中日期下的号源数据

7. 微信支付:Qrcode

image-20230828190100989

  • 每个订单有对应的订单id,通过对应的订单id获取唯一对应的订单二维码
  • 根据服务器返回的二维码信息通过Qrcode.js生成二维码图片
  • 调用qrcode的相关API库,传入对应的参数
  • 保存生成的二维码图片地址
//打开二维码支付对话框
const openDialog = async () => {
    dialogVisible.value = true
    //获取支付需要使用二维码信息
    let result: QrCode = await reqQrcode($route.query.orderId as string)
    //更具服务器返回二维码信息生成二维码图片
    imgUrl.value = await QRCode.toDataURL(result.data.codeUrl)
    //设置定时器每间隔2s发起请求 查询订单是否支付
    timer.value = setInterval(async () => {
        let result: PayReslt = await reqQueryPayState($route.query.orderId as string)
        if (result.data === true) {
            //关闭对话框
            dialogVisible.value = false
            //提示信息
            ElMessage({
                type: 'success',
                message: '支付成功'
            })
            //清除定时器
            clearInterval(timer.value)
            //再次获取订单详情的数据
            getOrderInfo()
        }
    }, 2000)
}

image-20230828183349488

  • 当打开支付页面时,就要开启定时器,每个两秒发一次请求用于询问订单是否支付
  • 直到支付成功后清除定时器

8. 就诊人管理

8.1 级联选择器选择多级地址信息

image-20230828183639784

 <el-cascader :props="props" v-model="userParams.addressSelected" />
//级联选择器地址信息方法
const props: CascaderProps = {
    lazy: true, //懒加载数据
    //加载级联选择器数据方法
    async lazyLoad(node: any, resolve: any) {
        let result: any = await reqCity(node.data.id || '86')
        //整理数据
        let showData = result.data.map((item: any) => {
            return {
                id: item.id,
                label: item.name,
                value: item.value,
                leaf: !item.hasChildren
            }
        })
        //注入组件需要展示的数据
        resolve(showData)
    }
}
  • props是级联选择器内置配置参数进行设置的对象
  • lazy属性设置为true,表示开启懒加载
  • 定义一个lazyLoad方法,用于加载级联选择器的数据,接受两个参数node和resolve回调
  • node表示当前选中的节点信息,resolve表示用于回调的函数
  • 方法内部通过id获取城市信息,为一级省份
  • 再使用map方法对城市数据进行整理,将id、name、value和是否有子级节点的信息映射到一个新的对象中,并存储在showData数组中
  • 最后,调用resolve函数,将整理后的数据传入,以便组件进行展示

8.2 就诊人信息收集

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rbXCrJoP-1693303620252)(C:/Users/Cai123/AppData/Roaming/Typora/typora-user-images/image-20230828184821995.png)]

image-20230828183537333

//watch监听数据
watch(
    () => userArr.value,
    () => {
        //如果是从预约挂号那里跳转过来 监听数据变化 根据id找到对应要修改的人
        if ($route.query.type === 'edit') {
            let user = userArr.value.find((item: any) => {
                return item.id == $route.query.id
            })

            //收集数据
            Object.assign(userParams, user)
        }
    }
)
  • Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

  • 当在选择就诊人信息时候,点击修改信息按钮,跳转到对应页面,要收集原先的数据信息

  • 需要通过watch监听userArr,判断路径是否是从预约挂号跳转过来的

  • 通过find方法从所有就诊人中找到对应选中修改的就诊人

  • 将其信息通过object.assign方法进行收集并展示

9. 挂号订单

image-20230828185126402

  • 调用接口信息展示即可

10. 路由鉴权

//路由鉴权: 路由守卫
import router from './router'
//引入大仓库
import pinia from '@/store'
//引入进度条
//@ts-ignore
import Nprogress from 'nprogress'
//引入用户相关的仓库
import useUserStore from '@/store/modules/user'
let userStore = useUserStore(pinia)
//引入进度条样式
import 'nprogress/nprogress.css'
//进度条的加载小圆球不要
Nprogress.configure({ showSpinner: false })
//存储用户未登录可以访问路由得路径
let whiteList = [
    '/home',
    '/hospital/register',
    '/hospital/detail',
    '/hospital/notice',
    '/hospital/close',
    '/hospital/search'
]

//前置守卫
router.beforeEach((to, from, next) => {
    //访问路由组件的之前,进度条开始动
    Nprogress.start()
    //动态设置网页左上角的标题
    //@ts-ignore
    document.title = to.meta.title
    //判断用户是否登录-token
    let token = userStore.userInfo.token
    if (token) {
        next()
    } else {
        //用户未登录
        if (whiteList.includes(to.path)) {
            next()
        } else {
            //登录组件
            userStore.visiable = true
            next({ path: '/home', query: { redirect: to.fullPath } })
        }
    }
})

//后置守卫
router.afterEach((to, from) => {
    //访问路由组件成功,进度条消失
    Nprogress.done()
})

三:规范代码格式和提交规范

  • eslint
  • prettier
  • cz-git

3.1 prettier

module.exports = {
  singleQuote: true, // 使用单引号, 默认false(在jsx中配置无效, 默认都是双引号)
  semi: false, // 使用分号, 默认true
  printWidth: 120, //  每行超过多少字符自动换行
  arrowParens: 'avoid', // avoid 能省略括号的时候就省略 例如x => x
  bracketSpacing: true, // 对象中的空格 默认true
  trailingComma: 'none', // all 包括函数对象等所有可选
  tabWidth: 4, // tab缩进大小,默认为2
  useTabs: false, // 使用tab缩进,默认false
  htmlWhitespaceSensitivity: 'ignore',
  // 对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
  bracketSpacing: true
}

3.2 eslint

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-essential',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended' // 解决ESlint和Prettier冲突
  ],
  overrides: [],
  // 配置支持 vue 和 ts
  parser: 'vue-eslint-parser',
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    parser: '@typescript-eslint/parser'
  },
  plugins: ['vue', '@typescript-eslint'],
  rules: {
    '@typescript-eslint/no-explicit-any': 'off', // 禁止使用该any类型。
    '@typescript-eslint/no-unused-vars': 'off', //禁止未使用的变量
    'vue/valid-template-root': 'off',
    'vue/no-v-html': 'off',
    'prefer-const': 'off',
    '@typescript-eslint/ban-types': 'off',
    '@typescript-eslint/no-empty-function': 'off',
    '@typescript-eslint/ban-ts-comment': 'off',
    'vue/multi-word-component-names': 'off',
    endOfLine: 'off', // 添加忽略换行格式的检查。
    'vue/require-default-prop': 'off' // props 需要设置默认值
  }
}

3.3 commitlintrc.js

// .commitlintrc.js
module.exports = {
  rules: {
    // @see: https://commitlint.js.org/#/reference-rules
  },
  prompt: {
    messages: {
      type: '选择你要提交的类型 :',
      scope: '选择一个提交范围(可选):',
      customScope: '请输入自定义的提交范围 :',
      subject: '填写简短精炼的变更描述 :\n',
      body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
      breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
      footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
      confirmCommit: '是否提交或修改commit ?'
    },
    types: [
      { value: 'feat', name: 'feat:        新增功能 | A new feature', emoji: '✨' },
      { value: 'fix', name: 'fix:         修复缺陷 | A bug fix', emoji: '🐛' },
      { value: 'docs', name: 'docs:        文档更新 | Documentation only changes', emoji: '📄' },
      {
        value: 'style',
        name: 'style:       代码格式 | Changes that do not affect the meaning of the code',
        emoji: '💄'
      },
      {
        value: 'refactor',
        name: 'refactor:    代码重构 | A code change that neither fixes a bug nor adds a feature',
        emoji: '♻️'
      },
      { value: 'perf', name: 'perf:        性能提升 | A code change that improves performance', emoji: '⚡️' },
      { value: 'test', name: 'test:        测试相关 | Adding missing tests or correcting existing tests', emoji: '✅' },
      {
        value: 'build',
        name: 'build:       构建相关 | Changes that affect the build system or external dependencies',
        emoji: '📦️'
      },
      { value: 'ci', name: 'ci:          持续集成 | Changes to our CI configuration files and scripts', emoji: '🎡' },
      { value: 'revert', name: 'revert:      回退代码 | Revert to a commit', emoji: '⏪️' },
      {
        value: 'chore',
        name: 'chore:       其他修改 | Other changes that do not modify src or test files',
        emoji: '🔨'
      }
    ],
    useEmoji: true,
    // scope 类型(定义之后,可通过上下键选择)
    scopes: [
      ['components', '组件相关'],
      ['hooks', 'hook 相关'],
      ['utils', 'utils 相关'],
      ['element-ui', '对 element-ui 的调整'],
      ['styles', '样式相关'],
      ['deps', '项目依赖'],
      ['auth', '对 auth 修改'],
      ['other', '其他修改']
    ].map(([value, description]) => {
      return {
        value,
        name: `${value.padEnd(30)} (${description})`
      }
    }),

    // 是否允许自定义填写 scope,在 scope 选择的时候,会有 empty 和 custom 可以选择。
    allowCustomScopes: true,

    // 跳过要询问的步骤
    skipQuestions: ['body', 'breaking', 'footer'],
    subjectLimit: 100, // subject 限制长度
    // 设置只有 type 选择了 feat 或 fix,才询问 breaking message
    allowBreakingChanges: ['feat', 'fix'],

    issuePrefixs: [
      // 如果使用 gitee 作为开发管理
      { value: 'link', name: 'link:     链接 ISSUES 进行中' },
      { value: 'comment', name: 'comment: 评论 ISSUES' },
      { value: 'closed', name: 'closed:   标记 ISSUES 已完成' }
    ]
  }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

视频融合平台EasyCVR视频汇聚平台关于小区高空坠物安全实施应用方案设计

近年来&#xff0c;随着我国城市化建设的推进&#xff0c;高楼大厦越来越多&#xff0c;高空坠物导致的伤害也屡见不鲜&#xff0c;严重的影响到人们的生命安全。像在日常生活中一些不起眼的小东西如烟头、鸡蛋、果核、易拉罐&#xff0c;看似伤害不大&#xff0c;但只要降落的…

Go【gin和gorm框架】实现紧急事件登记的接口

简单来说&#xff0c;就是接受前端微信小程序发来的数据保存到数据库&#xff0c;这是我写的第二个接口&#xff0c;相比前一个要稍微简单一些&#xff0c;而且因为前端页面也是我写的&#xff0c;参数类型自然是无缝对接_ 前端页面大概长这个样子 先用apifox模拟发送请求测试…

①matlab的命令掌握

目录 输入命令 命名变量 保存和加载变量 使用内置的函数和常量 输入命令 1.您可以通过在命令行窗口中 MATLAB 提示符 (>>) 后输入命令 任务 使用命令 3*5 将数值 3 和 5 相乘。 答案 3*5 2.除非另有指定&#xff0c;否则 MATLAB 会将计算结果存储在一个名为 ans…

美团面试拷打:ConcurrentHashMap 为何不能插入 null?HashMap 为何可以?

周末的时候,有一位小伙伴提了一些关于 ConcurrentHashMap 的问题,都是他最近面试遇到的。原提问如下(星球原贴地址:https://t.zsxq.com/11jcuezQs ): 整个提问看着非常复杂,其实归纳来说就是两个问题: ConcurrentHashMap 为什么 key 和 value 不能为 null?ConcurrentH…

MongoDB Long 类型 shell 查询

场景 1、某数据ID为Long类型&#xff0c;JAVA 定义实体类 Id Long id 2、查询数据库&#xff0c;此数据存在 3、使用 shell 查询&#xff0c;查不到数据 4、JAVA代码查询Query.query 不受任何影响 分析 尝试解决&#xff08;一&#xff09; long 在 mongo中为 int64 类型…

clickhouse(十四、分布式DDL阻塞及同步阻塞问题)

文章目录 一、分布式ddl 阻塞、超时现象验证方法解决方案 二、副本同步阻塞现象验证解决方案 一、分布式ddl 阻塞、超时 现象 在clickhouse 集群的操作中&#xff0c;如果同时执行一些重量级变更语句&#xff0c;往往会引起阻塞。 一般是由于节点堆积过多耗时的ddl。然后抛出…

论文阅读:Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks

前言 要弄清MAML怎么做&#xff0c;为什么这么做&#xff0c;就要看懂这两张图。先说MAML**在做什么&#xff1f;**它是打着Mate-Learing的旗号干的是few-shot multi-task Learning的事情。具体而言就是想训练一个模型能够使用很少的新样本&#xff0c;快速适应新的任务。 定…

PCB电路板电压电流监测软件

PCB电路板电流监测软件详细设计说明书是一个详细描述软件系统设计和实现的文档&#xff0c;它提供了软件系统的架构、功能模块、接口设计、数据存储和处理、界面设计、数据库设计、系统测试、部署和维护计划等方面的详细信息。模拟量采集/老化房采集软件 该文档的目的是为了确保…

深入解析文件系统原理(inode,软硬链接区别)

第四阶段提升 时 间&#xff1a;2023年8月29日 参加人&#xff1a;全班人员 内 容&#xff1a; 深入解析文件系统原理 目录 一、Inode and Block概述 &#xff08;一&#xff09;查看文件的inode信息&#xff1a;stat &#xff08;二&#xff09;Atime、Mtime、Ctime详…

计算机网络aaaaaaa

差错检测 在一段时间内&#xff0c;传输错误的比特占所传输比特总数的比率称为误码率BER(Bit Error Rate) 11111111111111111111111111111111111111111111111111111111111111111111111111111111 11111111111111111111111111111111111111111111111111111111111111111111111111…

「Vue|网页开发|前端开发」02 从单页面到多页面网站:使用路由实现网站多个页面的展示和跳转

本文主要介绍如何使用路由控制来实现将一个单页面网站扩展成多页面网站&#xff0c;包括页面扩展的逻辑&#xff0c;vue的官方路由vue-router的基本用法以及扩展用法 文章目录 本系列前文传送门一、场景说明二、基本的页面扩展页面扩展是在扩什么创建新页面的代码&#xff0c;…

Linux内核源码分析 (3)调度器的实现

Linux内核源码分析 (3)调度器的实现 文章目录 Linux内核源码分析 (3)调度器的实现一、概述二、调度器数据结构1、task_struct中与调度有关的的成员2、调度器类3、就绪队列4、调度实体 三、处理优先级1、优先级的内核表示2、计算优先级3、计算负荷权重 四、核心调度器1、周期性调…

网络安全(黑客技术)学习手册

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟…

VBA技术资料MF48:VBA_在Excel中将列号与字母转换

【分享成果&#xff0c;随喜正能量】除非自己的认知获得了改变和刷新&#xff0c;否则&#xff0c;人们常说的“顺应自己的内心”&#xff0c;顺的不过是一颗旧心&#xff0c;一颗惯性的&#xff0c;充满了各种习性的套路之心。与“顺应自己的内心”恰恰相反&#xff0c;人要用…

自动化PLC工程师能否转到c#上位机开发?

成功从自动化PLC工程师转向C#上位机开发的经历可能因人而异&#xff0c;以下是一些分享的思路和建议&#xff1a;扩展编程技能&#xff1a;学习C#语言和相关的开发工具和框架&#xff0c;掌握语言的基础知识和常用的编程技巧。可以通过在线教程、培训课程、书籍等途径进行学习&…

c# modbus CRC计算器(查表法)

一、简介&#xff1a; 本案例为crc计算器&#xff0c;通过查表法计算出结果 1.窗体后台源代码 using Crc; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text…

利用SSL证书的SNI特性建立自己的爬虫ip服务器

今天我要和大家分享一个关于自建多域名HTTPS爬虫ip服务器的知识&#xff0c;让你的爬虫ip服务器更加强大&#xff01;无论是用于数据抓取、反爬虫还是网络调试&#xff0c;自建一个支持多个域名的HTTPS爬虫ip服务器都是非常有价值的。本文将详细介绍如何利用SSL证书的SNI&#…

AI助力智能安检,基于图像目标检测实现危险品X光智能安全检测系统

基于AI相关的技术来对一些重复性的但是又比较重要的工作来做智能化助力是一个非常有潜力的场景&#xff0c;关于这方面的项目开发实践在我之前的文章中也有不少的实践&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a;《AI助力智能安检&#xff0c;基于目标检测模型实现…

Java面试题—2023年8月24日—YDZH

2023-08-24 10:54:28 北京 yī do zh h 答案仅供参考&#xff0c;博主仅记录发表&#xff0c;没有实际查询&#xff0c;不保证正确性。 面试题&#xff1a; 1、请你谈谈关于 Synchronized 和 lock ? 2、请简单描述一下类的加载过程?类加载器有几个种&#xff0c;分别作用是什…

DC电源模块不同的尺寸可以适应实际应用场景

BOSHIDA DC电源模块不同的尺寸可以适应实际应用场景 DC电源模块是现代电子设备的必备部件之一&#xff0c;其可提供稳定的直流电源&#xff0c;保证电子设备正常运行。DC电源模块尺寸的选择直接影响到其适应的应用场景及其性能表现。本文将从尺寸方面分析DC电源模块的适应性&a…