初始化

master
飘泊客 1 year ago
parent d94846450e
commit d31cfd561c

@ -1 +1,10 @@
VITE_SERVICE_ENV=dev
###
# @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
# @Date: 2023-07-28 16:10:52
# @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
# @LastEditTime: 2023-08-08 18:10:57
# @FilePath: \byhl-zt-app\.env.development
# @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
###
VITE_SERVICE_ENV = dev
VITE_APP_BASE_API = '/api'

@ -1 +1,2 @@
VITE_SERVICE_ENV=prod
VITE_SERVICE_ENV = prod
VITE_APP_BASE_API = '/api'

@ -1 +0,0 @@
VITE_SERVICE_ENV=test

@ -1,18 +1,28 @@
{
"extends": "@antfu",
"root": true,
"env": {
"es2021": true,
"node": true,
"browser": false
},
"extends": [
"eslint:recommended",
/** @see https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#recommended-configs */
"plugin:@typescript-eslint/recommended",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"ignorePatterns": ["types/env.d.ts", "node_modules/**", "**/dist/**"],
"rules": {
// if else try catch 风格
// ```
// try { try {
// loading() loading()
// } ==> } catch (e) {
// catch (e) { hideLoading()
// hideLoading() }
// }
// ```
"@typescript-eslint/brace-style": ["error", "1tbs"],
// if else 必须添加{} if()do() => if(){ do() }
"curly":["error", "multi-line"]
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/consistent-type-imports": "error",
"vue/multi-word-component-names": "off",
"vue/no-v-html": "off"
}
}
}

@ -4,7 +4,3 @@
* [UnoCSS](https://github.com/unocss/unocss) - 高性能且极具灵活性的即时原子化 CSS 引擎
* [unocss-preset-weapp](https://github.com/MellowCo/unocss-preset-weapp) - UnoCSS小程序预设
* [API 自动加载](https://github.com/antfu/unplugin-auto-import) - 直接使用 Composition API 无需引入
* ![img.png](img.png)
![img_1.png](img_1.png)
![img_2.png](img_2.png)
* ![img_3.png](img_3.png)

20
components.d.ts vendored

@ -7,21 +7,41 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
AccountLoginForm: typeof import('./src/components/login/AccountLoginForm.vue')['default']
AssetsList: typeof import('./src/components/home/AssetsList.vue')['default']
ConcatCaptcha: typeof import('./src/components/Captcha/ConcatCaptcha.vue')['default']
CpIcon: typeof import('./src/components/CpIcon.vue')['default']
DoctorCard: typeof import('./src/components/home/DoctorCard.vue')['default']
FollowDoctor: typeof import('./src/components/home/FollowDoctor.vue')['default']
KnowledgeCard: typeof import('./src/components/home/KnowledgeCard.vue')['default']
KnowledgeList: typeof import('./src/components/home/KnowledgeList.vue')['default']
RotateCaptcha: typeof import('./src/components/Captcha/RotateCaptcha.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SliderCaptcha: typeof import('./src/components/Captcha/SliderCaptcha.vue')['default']
SssetsList: typeof import('./src/components/home/SssetsList.vue')['default']
VanActionSheet: typeof import('vant/es')['ActionSheet']
VanButton: typeof import('vant/es')['Button']
VanCell: typeof import('vant/es')['Cell']
VanCellGroup: typeof import('vant/es')['CellGroup']
VanCol: typeof import('vant/es')['Col']
VanDatePicker: typeof import('vant/es')['DatePicker']
VanField: typeof import('vant/es')['Field']
VanForm: typeof import('vant/es')['Form']
VanIcon: typeof import('vant/es')['Icon']
VanImage: typeof import('vant/es')['Image']
VanList: typeof import('vant/es')['List']
VanPopup: typeof import('vant/es')['Popup']
VanRow: typeof import('vant/es')['Row']
VanSearch: typeof import('vant/es')['Search']
VanStep: typeof import('vant/es')['Step']
VanSteps: typeof import('vant/es')['Steps']
VanSticky: typeof import('vant/es')['Sticky']
VanSwipe: typeof import('vant/es')['Swipe']
VanSwipeItem: typeof import('vant/es')['SwipeItem']
VanTab: typeof import('vant/es')['Tab']
VanTabs: typeof import('vant/es')['Tabs']
VanTag: typeof import('vant/es')['Tag']
WordClickCaptcha: typeof import('./src/components/Captcha/WordClickCaptcha.vue')['default']
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

14643
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -47,6 +47,7 @@
"@dcloudio/uni-quickapp-webview": "3.0.0-alpha-3050420220804004",
"@dcloudio/uni-ui": "^1.4.20",
"axios": "^1.4.0",
"crypto-js": "^4.1.1",
"lodash": "1.3.1",
"moment": "^2.29.4",
"pinia": "^2.0.36",
@ -62,6 +63,7 @@
"@dcloudio/uni-cli-shared": "3.0.0-alpha-3050420220804004",
"@dcloudio/uni-stacktracey": "3.0.0-alpha-3050420220804004",
"@dcloudio/vite-plugin-uni": "3.0.0-alpha-3050420220804004",
"@types/crypto-js": "^4.1.1",
"@types/node": "^18.6.4",
"eslint": "^8.21.0",
"sass": "^1.54.8",

@ -1,3 +1,11 @@
<!--
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-01 18:05:55
* @FilePath: \byhl-zt-app\src\App.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<script setup lang="ts">
import {
Navigate
@ -34,6 +42,7 @@
<style lang="scss">
@import '@/static/reset.scss';
@import "@/static/icons/iconfont.css";
.uno-start {
--un: 0;
@ -43,4 +52,4 @@
.uno-end {
--un: 0;
}
</style>
</style>

@ -0,0 +1,45 @@
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-08-07 16:15:41
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-08 17:33:54
* @FilePath: \byhl-zt-app\src\api\captcha.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import type { CaptchaConfig } from '@/components/Captcha/types'
import { LoginResult } from '@/types/user'
import request from '@/utils/request'
export interface CaptchaData {
id: string
captcha: {
backgroundImage: string
templateImage: string
backgroundImageWidth: number
backgroundImageHeight: number
sliderImageWidth: number
sliderImageHeight: number
data: {
randomY?: string
}
}
}
/**
*
* @param type
* @returns
*/
export function captchaGen(type?: string) {
return request.get<CaptchaData>('/captcha/tianai/gen', { params: { type: type } })
}
/**
*
* @param id id
* @param data true:/false:
* @returns
*/
export function captchaCheck(id: string, data: CaptchaConfig) {
return request.post<boolean>('/captcha/tianai/check', data, { params: { id } })
}

@ -1,8 +1,32 @@
import request from '@/utils/request'
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-08 16:36:08
* @FilePath: \byhl-zt-app\src\api\login.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import request from '@/utils/request'
import type { OAuth2LoginParam } from '@/components/Captcha/types'
import { LoginResult } from '@/types/user'
const BASIC_AUTHORIZATION = 'Basic dWk6dWk='
export const loginAPI = (mobile: string, password: string) => {
return request.post('login/password', {
mobile,
password
})
}
/**
*
* @param parameter
*/
export function accountLogin(parameter: OAuth2LoginParam) {
return request<LoginResult>({
url: '/oauth2/token',
method: 'POST',
headers: {
Authorization: BASIC_AUTHORIZATION
},
params: parameter
})
}

@ -0,0 +1,157 @@
<template>
<div v-show="visible" class="captcha-mask">
<div class="slider concat">
<div class="content">
<div ref="concatImgDivRef" :style="concatImgDivStyle" class="concat-img-div"></div>
<div ref="bgImgDivRef" :style="bgImgDivStyle" class="bg-img-div"></div>
</div>
<div class="slider-move">
<div class="slider-move-track">拖动滑块完成拼图</div>
<div
class="slider-move-btn"
:style="sliderMoveBtnStyle"
@mousedown="down"
@touchstart.prevent="down"
></div>
</div>
<div class="bottom">
<div class="close-btn" style="margin-right: 6px" @click="closeCaptcha"></div>
<div class="refresh-btn" @click="refreshCaptcha"></div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, nextTick } from 'vue'
import { captchaCheck, type CaptchaData, captchaGen } from '@/api/captcha'
import type { CaptchaConfig } from '@/components/Captcha/types'
import { useCaptcha } from '@/components/Captcha/useCaptcha'
import type { CSSProperties } from 'vue'
const props = defineProps<{
onSuccess?: (id: string) => void
}>()
//
const visible = ref(false)
function showCaptcha() {
visible.value = true
}
function closeCaptcha() {
visible.value = false
}
const bgImgDivRef = ref()
const concatImgDivRef = ref()
const captchaData = ref<CaptchaData>()
// X
const moveX = ref(0)
//
const sliderMoveBtnActive = ref(false)
// div
const bgImgDivStyle = ref<CSSProperties>({})
// div
const concatImgDivStyle = ref<CSSProperties>({ transform: 'translateX(0px)' })
//
const sliderMoveBtnStyle = computed<CSSProperties>(() => ({
transform: `translateX(${moveX.value}px)`,
backgroundPosition: sliderMoveBtnActive.value ? '-5px 31.0092%' : '-5px 11.79625%'
}))
function reset() {
moveX.value = 0
sliderMoveBtnActive.value = false
concatImgDivStyle.value.transform = 'translateX(0px)'
}
/* 刷新验证码 */
function refreshCaptcha() {
reset()
captchaGen('CONCAT').then(res => {
console.log("🚀 ~ file: ConcatCaptcha.vue:73 ~ captchaGen ~ res:", res)
captchaData.value = res
bgImgDivStyle.value.backgroundImage = `url(${res.captcha.backgroundImage})`
concatImgDivStyle.value.backgroundImage = `url(${res.captcha.backgroundImage})`
concatImgDivStyle.value.backgroundPosition = '0px 0px'
const backgroundImageHeight = res.captcha.backgroundImageHeight
const height =
((backgroundImageHeight - res.captcha.data.randomY!) / backgroundImageHeight) * 159
concatImgDivStyle.value.height = `${height}px`
nextTick(() => {
initConfig(
bgImgDivRef.value.clientWidth,
bgImgDivRef.value.clientHeight,
concatImgDivRef.value.width,
concatImgDivRef.value.height,
206
)
})
})
}
function doDown() {
sliderMoveBtnActive.value = true
}
function doMove(config: CaptchaConfig) {
moveX.value = config.moveX!
concatImgDivStyle.value.backgroundPositionX = `${moveX.value}pX`
}
function valid(config: CaptchaConfig) {
const data = {
bgImageWidth: config.bgImageWidth,
bgImageHeight: config.bgImageHeight,
templateImageWidth: config.templateImageWidth,
templateImageHeight: config.templateImageHeight,
startSlidingTime: config.startTime,
entSlidingTime: config.stopTime,
trackList: config.trackArr
}
const { id } = captchaData.value!
captchaCheck(id, data).then(res => {
if (res) {
props.onSuccess?.(id)
closeCaptcha()
} else {
refreshCaptcha()
}
})
}
const { initConfig, down } = useCaptcha({ doDown, doMove, valid })
defineExpose({
show() {
refreshCaptcha()
showCaptcha()
}
})
</script>
<style lang="scss" scoped>
@import './index.scss';
.concat {
.bg-img-div {
background-size: 100% 159px;
background-image: none;
background-position: 0 0;
z-index: 0;
}
}
.concat-img-div {
height: 100%;
width: 100%;
background-size: 100% 159px;
position: absolute;
transform: translate(0px, 0px);
z-index: 1;
}
</style>

@ -0,0 +1,145 @@
<template>
<div v-show="visible" class="captcha-mask">
<div class="slider rotate">
<div class="content">
<div class="bg-img-div">
<img ref="bgImgRef" alt="" :src="captchaData?.captcha.backgroundImage" />
</div>
<div class="rotate-img-div">
<img
ref="rotateImgRef"
:style="rotateImgStyle"
:src="captchaData?.captcha.templateImage"
alt=""
/>
</div>
</div>
<div class="slider-move">
<div class="slider-move-track">拖动滑块旋转正确位置</div>
<div
class="slider-move-btn"
:style="sliderMoveBtnStyle"
@mousedown="down"
@touchstart.prevent="down"
></div>
</div>
<div class="bottom">
<div class="close-btn" style="margin-right: 6px" @click="closeCaptcha"></div>
<div class="refresh-btn" @click="refreshCaptcha"></div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { captchaGen, captchaCheck, type CaptchaData } from '@/api/captcha'
import type { CaptchaConfig } from '@/components/Captcha/types'
import { useCaptcha } from '@/components/Captcha/useCaptcha'
import type { CSSProperties } from 'vue'
const props = defineProps<{
onSuccess?: (id: string) => void
}>()
//
const visible = ref(false)
function showCaptcha() {
visible.value = true
}
function closeCaptcha() {
visible.value = false
}
const bgImgRef = ref()
const rotateImgRef = ref()
const captchaData = ref<CaptchaData>()
// X
const moveX = ref(0)
//
const sliderMoveBtnActive = ref(false)
//
const rotateImgStyle = ref<CSSProperties>({ transform: 'rotate(0deg)' })
//
const sliderMoveBtnStyle = computed<CSSProperties>(() => ({
transform: `translateX(${moveX.value}px)`,
backgroundPosition: sliderMoveBtnActive.value ? '-5px 31.0092%' : '-5px 11.79625%'
}))
function reset() {
moveX.value = 0
sliderMoveBtnActive.value = false
rotateImgStyle.value = { transform: 'rotate(0deg)' }
}
/* 刷新验证码 */
function refreshCaptcha() {
reset()
captchaGen('ROTATE').then(res => {
captchaData.value = res
nextTick(() => {
initConfig(
206,
bgImgRef.value.height,
rotateImgRef.value.width,
rotateImgRef.value.height,
206
)
})
})
}
function doDown() {
sliderMoveBtnActive.value = true
}
function doMove(config: CaptchaConfig) {
moveX.value = config.moveX!
rotateImgStyle.value.transform = 'rotate(' + moveX.value / (config.end! / 360) + 'deg)'
}
function valid(config: CaptchaConfig) {
const data = {
bgImageWidth: config.bgImageWidth,
bgImageHeight: config.bgImageHeight,
templateImageWidth: config.templateImageWidth,
templateImageHeight: config.templateImageHeight,
startSlidingTime: config.startTime,
entSlidingTime: config.stopTime,
trackList: config.trackArr
}
const { id } = captchaData.value!
captchaCheck(id, data).then(res => {
if (res) {
props.onSuccess?.(id)
closeCaptcha()
} else {
refreshCaptcha()
}
})
}
const { initConfig, down } = useCaptcha({ doDown, doMove, valid })
defineExpose({
show() {
refreshCaptcha()
showCaptcha()
}
})
</script>
<style lang="scss" scoped>
@import './index.scss';
.rotate-img-div {
height: 100%;
position: absolute;
transform: rotate(0deg);
margin-left: 50px;
}
.rotate-img-div img {
height: 100%;
}
</style>

@ -0,0 +1,144 @@
<template>
<div v-show="visible" class="captcha-mask">
<div class="slider">
<div class="content">
<div class="bg-img-div">
<img ref="bgImgRef" alt="" :src="captchaData?.captcha.backgroundImage" />
</div>
<div class="slider-img-div">
<img
ref="sliderImgRef"
:style="sliderImgStyle"
:src="captchaData?.captcha.templateImage"
alt=""
/>
</div>
</div>
<div class="slider-move">
<div class="slider-move-track">拖动滑块完成拼图</div>
<div
class="slider-move-btn"
:style="sliderMoveBtnStyle"
@mousedown="down"
@touchstart.prevent="down"
></div>
</div>
<div class="bottom">
<div class="close-btn" style="margin-right: 6px" @click="closeCaptcha"></div>
<div class="refresh-btn" @click="refreshCaptcha"></div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { captchaGen, captchaCheck, type CaptchaData } from '@/api/captcha'
import type { CaptchaConfig } from '@/components/Captcha/types'
import { useCaptcha } from '@/components/Captcha/useCaptcha'
import type { CSSProperties } from 'vue'
const props = defineProps<{
onSuccess?: (id: string) => void
}>()
//
const visible = ref(false)
function showCaptcha() {
visible.value = true
}
function closeCaptcha() {
visible.value = false
}
const bgImgRef = ref()
const sliderImgRef = ref()
const captchaData = ref<CaptchaData>()
// X
const moveX = ref(0)
//
const sliderMoveBtnActive = ref(false)
//
const sliderImgStyle = computed<CSSProperties>(() => ({
transform: `translateX(${moveX.value}px)`
}))
//
const sliderMoveBtnStyle = computed<CSSProperties>(() => ({
transform: `translateX(${moveX.value}px)`,
backgroundPosition: sliderMoveBtnActive.value ? '-5px 31.0092%' : '-5px 11.79625%'
}))
function reset() {
moveX.value = 0
sliderMoveBtnActive.value = false
}
/* 刷新验证码 */
function refreshCaptcha() {
reset()
captchaGen().then(res => {
console.log("🚀 ~ file: SliderCaptcha.vue:80 ~ captchaGen ~ res:", res)
captchaData.value = res
nextTick(() => {
initConfig(
bgImgRef.value.width,
bgImgRef.value.height,
sliderImgRef.value.width,
sliderImgRef.value.height,
206
)
})
})
}
function doDown() {
sliderMoveBtnActive.value = true
}
function doMove(config: CaptchaConfig) {
moveX.value = config.moveX!
}
function valid(config: CaptchaConfig) {
const {
bgImageWidth,
bgImageHeight,
templateImageWidth,
templateImageHeight,
startTime: startSlidingTime,
stopTime: endSlidingTime,
trackArr: trackList
} = config
const captchaCheckConfig = {
bgImageWidth,
bgImageHeight,
templateImageWidth,
templateImageHeight,
startSlidingTime,
endSlidingTime,
trackList
}
const { id } = captchaData.value!
captchaCheck(id, captchaCheckConfig).then(res => {
if (res) {
props.onSuccess?.(id)
closeCaptcha()
} else {
refreshCaptcha()
}
})
}
const { initConfig, down } = useCaptcha({ doDown, doMove, valid })
defineExpose({
show() {
refreshCaptcha()
showCaptcha()
}
})
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

@ -0,0 +1,221 @@
<template>
<view v-show="visible" class="captcha-mask">
<view class="slider word-click">
<view class="slider-move">
<text class="slider-move-span">请依次点击:</text>
<img :src="sliderImageUrl" class="tip-img" alt="" />
</view>
<view ref="contentRef" class="content" @click="wordClick">
<view ref="bgImgDivRef" class="bg-img-div">
<img ref="bgImgRef" alt="" :src="backgroundImageUrl" />
</view>
<view class="bg-click-div">
<text
v-for="item in clickPositions"
:key="item.number"
class="click-span"
:style="`left:${item.left}px;top:${item.top}px`"
>
{{ item.number }}
</text>
</view>
</view>
<view class="bottom">
<view class="close-btn" style="margin-right: 6px" @click="closeCaptcha"></view>
<view class="refresh-btn" @click="refreshCaptcha"></view>
</view>
</view>
</view>
</template>
<script setup lang="ts">
import { captchaGen, captchaCheck, type CaptchaData } from '@/api/captcha'
import type { CaptchaConfig, Track } from '@/components/Captcha/types'
const props = defineProps<{
onSuccess?: (id: string) => void
}>()
//
const visible = ref(false)
function showCaptcha() {
visible.value = true
}
function closeCaptcha() {
visible.value = false
}
const contentRef = ref()
const bgImgRef = ref()
const bgImgDivRef = ref()
const captchaData = ref<CaptchaData>()
const backgroundImageUrl = ref()
const sliderImageUrl = ref()
const tpImageUrl = ref()
let startSlidingTime: Date
let entSlidingTime: Date
const trackArr: Track[] = []
//
const clickCount = ref(0)
type ClickPosition = {
left: number
top: number
number: number
}
const clickPositions = ref<ClickPosition[]>([])
function wordClick(event: MouseEvent) {
if (clickCount.value >= 4) {
return
}
clickCount.value++
if (clickCount.value === 1) {
startSlidingTime = new Date()
// move
window.addEventListener('mousemove', move)
}
trackArr.push({
x: event.offsetX,
y: event.offsetY,
type: 'click',
t: new Date().getTime() - startSlidingTime.getTime()
})
const left = event.offsetX - 10
const top = event.offsetY - 10
clickPositions.value.push({ left: left, top: top, number: clickCount.value })
if (clickCount.value === 4) {
//
entSlidingTime = new Date()
window.removeEventListener('mousemove', move)
valid({
bgImageWidth: bgImgDivRef.value.clientWidth,
bgImageHeight: contentRef.value.clientHeight,
sliderImageWidth: -1,
sliderImageHeight: -1,
startTime: startSlidingTime,
stopTime: entSlidingTime,
trackArr: trackArr
})
}
}
function move(event: MouseEvent) {
trackArr.push({
x: event.offsetX,
y: event.offsetY,
t: new Date().getTime() - startSlidingTime.getTime(),
type: 'move'
})
}
function reset() {
startSlidingTime = new Date()
entSlidingTime = new Date()
trackArr.length = 0
clickPositions.value = []
clickCount.value = 0
window.removeEventListener('mousemove', move)
}
/* 刷新验证码 */
function refreshCaptcha() {
reset()
captchaGen('WORD_IMAGE_CLICK').then(res => {
console.log("🚀 ~ file: WordClickCaptcha.vue:128 ~ captchaGen ~ res:", res)
captchaData.value = res
backgroundImageUrl.value = res.captcha.backgroundImage
sliderImageUrl.value = res.captcha.templateImage
tpImageUrl.value = res.captcha.templateImage
})
}
function valid(config: CaptchaConfig) {
const data = {
bgImageWidth: config.bgImageWidth,
bgImageHeight: config.bgImageHeight,
templateImageWidth: config.templateImageWidth,
templateImageHeight: config.templateImageHeight,
startSlidingTime: config.startTime,
entSlidingTime: config.stopTime,
trackList: config.trackArr
}
const { id } = captchaData.value!
captchaCheck(id, data).then(res => {
if (res) {
props.onSuccess?.(id)
closeCaptcha()
} else {
refreshCaptcha()
}
})
}
defineExpose({
show() {
refreshCaptcha()
showCaptcha()
}
})
</script>
<style lang="scss" scoped>
@import './index.scss';
.slider.word-click {
height: 250px;
position: relative;
}
.word-click {
.bg-img-div {
z-index: 0;
}
.slider-move {
height: 40px;
margin: 0;
}
.bottom {
margin-top: 10px;
}
}
.bg-click-div {
z-index: 1;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.tip-img {
width: 130px;
position: absolute;
right: 5px;
}
.slider-move-span {
font-size: 18px;
display: inline-block;
height: 40px;
line-height: 40px;
}
.click-span {
position: absolute;
left: 0;
top: 0;
border-radius: 50px;
background-color: #409eff;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
color: #fff;
border: 2px solid #fff;
}
</style>

@ -0,0 +1,118 @@
.slider {
background-color: #fff;
width: 278px;
height: 285px;
z-index: 999;
box-sizing: border-box;
padding: 9px;
border-radius: 6px;
box-shadow: 0 0 11px 0 #999999;
}
.slider .content {
width: 100%;
height: 159px;
position: relative;
}
.bg-img-div {
width: 100%;
height: 100%;
position: absolute;
transform: translate(0px, 0px);
}
.slider-img-div {
height: 100%;
position: absolute;
transform: translate(0px, 0px);
}
.bg-img-div img {
width: 100%;
}
.slider-img-div img {
height: 100%;
}
.slider .slider-move {
height: 60px;
width: 100%;
margin: 11px 0;
position: relative;
}
.slider .bottom {
height: 19px;
width: 100%;
}
.refresh-btn,
.close-btn,
.slider-move-track,
.slider-move-btn {
background: url(@/static/sprite.1.2.4.png) no-repeat;
}
.refresh-btn,
.close-btn {
display: inline-block;
}
.slider-move .slider-move-track {
line-height: 38px;
font-size: 14px;
text-align: center;
white-space: nowrap;
color: #88949d;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
}
.slider {
user-select: none;
}
.slider-move .slider-move-btn {
transform: translate(0px, 0px);
background-position: -5px 11.79625%;
position: absolute;
top: -12px;
left: 0;
width: 66px;
height: 66px;
}
.slider-move-btn:hover,
.close-btn:hover,
.refresh-btn:hover {
cursor: pointer;
}
.bottom .close-btn {
width: 20px;
height: 20px;
background-position: 0 44.86874%;
}
.bottom .refresh-btn {
width: 20px;
height: 20px;
background-position: 0 81.38425%;
}
.captcha-mask {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 1009;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

@ -0,0 +1,4 @@
export { default as SliderCaptcha } from '@/components/Captcha/SliderCaptcha.vue'
export { default as RotateCaptcha } from '@/components/Captcha/RotateCaptcha.vue'
export { default as ConcatCaptcha } from '@/components/Captcha/ConcatCaptcha.vue'
export { default as WordClickCaptcha } from '@/components/Captcha/WordClickCaptcha.vue'

@ -0,0 +1,49 @@
import { LoginResult } from '@/types/user'
export interface CaptchaConfig {
startX?: number
startY?: number
type?: string
startTime?: Date
stopTime?: Date
trackArr?: Track[]
end?: number
bgImageWidth?: number
bgImageHeight?: number
templateImageWidth?: number
templateImageHeight?: number
movePercent?: number
moveX?: number
t?: number
}
export interface Track {
x: number
y: number
type: string
t: number
}
export interface CaptchaProps {
onSuccess?: (id: string) => void
}
export interface LoginFormInstance {
doLogin: (captchaId?: string) => Promise<LoginResult>
}
export interface AccountLoginParam {
username: string
password: string
grant_type: string
captchaId?: string
}
/**
*
*/
export interface MobileLoginParam {
mobile?: string
captcha?: string
}
export type OAuth2LoginParam = (AccountLoginParam | MobileLoginParam)

@ -0,0 +1,127 @@
import type { Track, CaptchaConfig } from '@/components/Captcha/types'
export const useCaptcha = (
options: {
doDown?: (captchaConfig: CaptchaConfig) => void
doMove?: (captchaConfig: CaptchaConfig) => void
valid?: (captchaConfig: CaptchaConfig) => void
} = {}
) => {
// 验证码配置
let currentCaptchaConfig: CaptchaConfig = {}
function initConfig(
bgImageWidth: number,
bgImageHeight: number,
sliderImageWidth: number,
sliderImageHeight: number,
end: number
) {
currentCaptchaConfig = {
startTime: new Date(),
trackArr: [],
movePercent: 0,
bgImageWidth,
bgImageHeight,
sliderImageWidth,
sliderImageHeight,
end
}
}
const down = (event: MouseEvent | TouchEvent) => {
const targetTouches = (event as TouchEvent)?.targetTouches
let startX = (event as MouseEvent)?.pageX
let startY = (event as MouseEvent)?.pageY
if (startX === undefined) {
startX = Math.round(targetTouches[0].pageX)
startY = Math.round(targetTouches[0].pageY)
}
currentCaptchaConfig.startX = startX
currentCaptchaConfig.startY = startY
const pageX = currentCaptchaConfig.startX
const pageY = currentCaptchaConfig.startY
const startTime = currentCaptchaConfig.startTime
const trackArr = currentCaptchaConfig.trackArr
trackArr!.push({
x: pageX - startX,
y: pageY - startY,
type: 'down',
t: new Date().getTime() - startTime!.getTime()
})
// pc
window.addEventListener('mousemove', move)
window.addEventListener('mouseup', up)
// 手机端
window.addEventListener('touchmove', move, false)
window.addEventListener('touchend', up, false)
options.doDown?.(currentCaptchaConfig)
}
function move(event: MouseEvent | TouchEvent) {
let touchMouseEvent: MouseEvent | Touch = event as MouseEvent
if (window.TouchEvent && event instanceof TouchEvent) {
touchMouseEvent = event.touches[0]
}
const pageX = Math.round(touchMouseEvent.pageX)
const pageY = Math.round(touchMouseEvent.pageY)
const startX = currentCaptchaConfig.startX as number
const startY = currentCaptchaConfig.startY as number
const startTime = currentCaptchaConfig.startTime as Date
const end = currentCaptchaConfig.end as number
const bgImageWidth = currentCaptchaConfig.bgImageWidth as number
const trackArr = currentCaptchaConfig.trackArr as unknown[]
let moveX = pageX - startX
const track = {
x: pageX - startX,
y: pageY - startY,
type: 'move',
t: new Date().getTime() - startTime.getTime()
}
trackArr.push(track)
if (moveX < 0) {
moveX = 0
} else if (moveX > end) {
moveX = end
}
currentCaptchaConfig.moveX = moveX
currentCaptchaConfig.movePercent = moveX / bgImageWidth
options.doMove?.(currentCaptchaConfig)
}
function up(event: MouseEvent | TouchEvent) {
let touchMouseEvent: MouseEvent | Touch = event as MouseEvent
window.removeEventListener('mousemove', move)
window.removeEventListener('mouseup', up)
window.removeEventListener('touchmove', move)
window.removeEventListener('touchend', up)
if (window.TouchEvent && event instanceof TouchEvent) {
touchMouseEvent = event.changedTouches[0]
}
currentCaptchaConfig.stopTime = new Date()
const pageX = Math.round(touchMouseEvent.pageX)
const pageY = Math.round(touchMouseEvent.pageY)
const startX = currentCaptchaConfig.startX as number
const startY = currentCaptchaConfig.startY as number
const startTime = currentCaptchaConfig.startTime as Date
const trackArr = currentCaptchaConfig.trackArr as Track[]
const track: Track = {
x: pageX - startX,
y: pageY - startY,
type: 'up',
t: new Date().getTime() - startTime.getTime()
}
trackArr.push(track)
options.valid?.(currentCaptchaConfig)
}
return {
initConfig,
down
}
}

@ -1,17 +1,19 @@
<!---->
<template>
<svg aria-hidden="true" class="cp-icon">
<svg aria-hidden="true" class="cp-icon" :style="{ width, height }">
<!-- #icon-文件夹名称-图片名称 -->
<use :href="`#icon-${name}`" />
<use :href="`#icon-${name}`" :fill="color" />
</svg>
</template>
<script setup lang="ts">
//name
interface Props {
name: string
name: string,
color?: string,
width?: string,
height?: string
}
defineProps < Props > ()
</script>
<style lang="scss" scoped>
@ -20,4 +22,4 @@
width: 1em;
height: 1em;
}
</style>
</style>

@ -0,0 +1,123 @@
<script setup lang="ts">
import CpIcon from '@/components/CpIcon.vue';
import { parseTime } from '@/utils/index'
import { Modal } from '@/plugins/Modal'
import {
ref
} from 'vue'
import type {
AssetsList
} from '@/types/consult'
import {
getKnowledgePage
} from '@/api/consult'
interface SearchObj {
searchVal: string | number
}
const props = defineProps<SearchObj>()
const emits = defineEmits(['clickDetail', 'toPlay'])
//
const list = ref<AssetsList>([
{ id: 1, name: '张三大大大大大大大大大大大大大大大大大大大大大大大大大大', state: 1, lastTime: 1690956863121, call: '18516647464', tag: ['人美', '温柔乡', '粘人', '毒蛇', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨',] },
{ id: 2, name: '张三大大大大大大大大大大大大大大大大大大大大大大大大大大', state: 1, lastTime: 1690956863121, call: '18516647464', tag: ['人美', '温柔乡', '粘人', '毒蛇', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨',] },
{ id: 3, name: '张三大大大大大大大大大大大大大大大大大大大大大大大大大大', state: 1, lastTime: 1690956863121, call: '18516647464', tag: ['人美', '温柔乡', '粘人', '毒蛇', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨',] },
{ id: 4, name: '张三大大大大大大大大大大大大大大大大大大大大大大大大大大', state: 1, lastTime: 1690956863121, call: '18516647464', tag: ['人美', '温柔乡', '粘人', '毒蛇', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨',] },
{ id: 5, name: '张三大大大大大大大大大大大大大大大大大大大大大大大大大大', state: 1, lastTime: 1690956863121, call: '18516647464', tag: ['人美', '温柔乡', '粘人', '毒蛇', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨',] },
{ id: 5, name: '张三大大大大大大大大大大大大大大大大大大大大大大大大大大', state: 1, lastTime: 1690956863121, call: '18516647464', tag: ['人美', '温柔乡', '粘人', '毒蛇', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨',] },
{ id: 5, name: '张三大大大大大大大大大大大大大大大大大大大大大大大大大大', state: 1, lastTime: 1690956863121, call: '18516647464', tag: ['人美', '温柔乡', '粘人', '毒蛇', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨',] },
{ id: 5, name: '张三大大大大大大大大大大大大大大大大大大大大大大大大大大', state: 1, lastTime: 1690956863121, call: '18516647464', tag: ['人美', '温柔乡', '粘人', '毒蛇', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨',] },
{ id: 5, name: '张三大大大大大大大大大大大大大大大大大大大大大大大大大大', state: 1, lastTime: 1690956863121, call: '18516647464', tag: ['人美', '温柔乡', '粘人', '毒蛇', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨', '话痨',] },
]);
//:true false()
const loading = ref(false);
//:falsw true
const finished = ref(false);
//
let params = {
current: 1,
pageSize: 10,
searchVal: ''
}
// onMounted(() => {
// console.log('22222222222222222222')
// })
//
const onLoad = async () => {
//
// setTimeout ajax
if (props.searchVal) {
params.searchVal = props.searchVal.toString()
}
const {
data
} = await getKnowledgePage(params)
if (params.searchVal) {
initList()
}
//list
list.value.push(...data.rows)
//
loading.value = false;
//
// ?
//1list===total
//2current===pageTotal
if (list.value.length === data.total) {
//
finished.value = true;
} else {
//?+1
params.current++
}
};
const clickDetail = (id: string) => {
emits('clickDetail', id)
}
const playCall = async (call: string) => {
emits('toPlay', call)
}
const initList = () => {
params.searchVal = ''
list.value = []
finished.value = false
params.current = 1
}
</script>
<template>
<view class="knowledge-list">
<van-list v-model:loading="loading" :finished="finished" finished-text="" @load="onLoad">
<!-- 列表数据 -->
<view class="mt-20rpx">
<view v-for="(item, index) in list" class="card-item bg-white p-15rpx mb-16rpx border-l-7 border-cyan-500" @click="clickDetail(item.id)">
<view class="flex items-center justify-between">
<view class="font-bold text-c5 text-sm van-ellipsis flex-initial pr-15rpx">{{ item.name }}</view>
<view class="flex-none"><uni-icons type="smallcircle-filled" :class="item.state == 0 ? '' : 'text-c7'" size="10rpx"></uni-icons>{{ item.state == 0 ? '' : '' }}</view>
</view>
<view class="flex py-15rpx justify-between">
<view class="flex-initial van-ellipsis">
<text class="block text-xs mb-10rpx">最后跟进{{ parseTime(item.lastTime) }}</text>
<!-- <text class="block text-xs">标签有意向咨询多次</text> -->
<view class="van-ellipsis">
<van-tag v-for="it in item.tag" type="primary" class="mr-5rpx">{{ it }}</van-tag>
</view>
</view>
<view class="flex-none" @click.stop="playCall(item.call)">
<uni-icons custom-prefix="iconfont" class="text-c6! block mt-6rpx active:text-c7!" type="icon-dianhua" size="36"></uni-icons>
</view>
</view>
</view>
</view>
</van-list>
</view>
</template>
<style lang="scss" scoped>
.CpIcon {
font-size: 48px;
margin-right: 5px;
}
</style>

@ -1,62 +0,0 @@
<script lang="ts" setup>
import type {
Doctor
} from '@/types/consult'
defineProps < {
item: Doctor
} > ()
</script>
<template>
<view class="doctor-card">
<van-image round :src="item.avatar" />
<p class="name">{{ item.name }}</p>
<p class="van-ellipsis">{{ item.hospitalName }} {{ item.depName }}</p>
<p>{{ item.positionalTitles }}</p>
<van-button round size="small" type="primary">
{{ item.likeFlag === 1 ? '已关注' : '+ 关注' }}
</van-button>
</view>
</template>
<style scoped lang="scss">
.doctor-card {
width: 135px;
height: 190px;
background: #fff;
border-radius: 20px;
box-shadow: 0px 0px 11px 0px rgba(229, 229, 229, 0.2);
text-align: center;
padding: 15px;
margin-left: 15px;
display: inline-block;
box-sizing: border-box;
>.van-image {
width: 58px;
height: 58px;
vertical-align: top;
border-radius: 50%;
margin: 0 auto 8px;
}
>p {
margin-bottom: 0;
font-size: 11px;
color: var(--cp-tip);
&.name {
font-size: 13px;
color: var(--cp-text1);
margin-bottom: 5px;
}
}
>.van-button {
padding: 0 12px;
height: 28px;
margin-top: 8px;
width: 72px;
}
}
</style>

@ -1,86 +0,0 @@
<script setup lang="ts">
import {
ref
} from 'vue'
import DoctorCard from './DoctorCard.vue'
import {
getDoctorPage
} from '@/api/consult'
import type {
DoctorList
} from '@/types/consult'
//
const list = ref < DoctorList > ([])
const getList = async () => {
const {
data
} = await getDoctorPage(({
current: 1,
pageSize: 5
}))
//5
list.value = data.rows
}
//1js
const width = ref(375)
onLoad(() => {
//
const windowResizeCallback = (res) => {
console.log('变化后的窗口宽度=' + res.size.windowWidth)
console.log('变化后的窗口高度=' + res.size.windowHeight)
width.value = res.size.windowWidth
}
uni.onWindowResize(windowResizeCallback)
getList()
})
</script>
<template>
<view class="follow-doctor">
<!-- 1头部 -->
<view className="head">
<p>推荐关注</p>
<a href="javascript:;"> 查看更多<i class="van-icon van-icon-arrow" /></a>
</view>
<!-- 2医生列表 -->
<view class="body">
<!-- swipe 组件 -->
<!-- width是用来指定单个item的宽度 -->
<!-- 问题:150是写死的 -->
<!-- 解决:基准比例(150/375)*当前屏幕宽度 做一个动态计算 -->
<van-swipe :autoplay="3000" :width="(150/375)*width" :loop="false" :show-indicators="false">
<van-swipe-item v-for="item in list" :key="item.id">
<!-- 单个医生的信息介绍 -->
<doctor-card :item="item" />
</van-swipe-item>
</van-swipe>
</view>
</view>
</template>
<style lang="scss" scoped>
.follow-doctor {
background-color: var(--cp-bg);
height: 250px;
.head {
display: flex;
justify-content: space-between;
height: 45px;
align-items: center;
padding: 0 15px;
font-size: 13px;
>a {
color: var(--cp-tip);
}
}
.body {
width: 100%;
overflow: hidden;
}
}
</style>

@ -1,138 +0,0 @@
<script setup lang="ts">
import type {
Knowledge
} from '@/types/consult'
defineProps < {
item: Knowledge
} > ()
</script>
<template>
<view class="knowledge-card van-hairline--bottom">
<view class="head">
<van-image round class="avatar" :src="item.creatorAvatar"></van-image>
<view class="info">
<p class="name">{{ item.creatorName }}</p>
<p class="dep van-ellipsis">
{{ item.creatorHospatalName }} {{ item.creatorDep }} {{ item.creatorTitles }}
</p>
</view>
<van-button class="btn" size="small" round>
{{ item.likeFlag === 1 ? '已关注' : '+ 关注' }}
</van-button>
</view>
<view class="body">
<h3 class="title van-ellipsis">{{ item.title }}</h3>
<p class="tag">
<span v-for="(tag, i) in item.topics" :key="i"># {{ tag }}</span>
</p>
<p class="intro van-multi-ellipsis--l2">{{ item.content.replace(/<[^>]+>/g, '') }}</p>
<view class="imgs" :class="{ large: item.coverUrl.length === 1 }">
<van-image fit="cover" v-for="(url, i) in item.coverUrl" :key="i" :src="url" />
</view>
<p class="logs">
<span>{{ item.collectionNumber }} 收藏</span>
<span>{{ item.commentNumber }} 评论</span>
</p>
</view>
</view>
</template>
<style lang="scss" scoped>
.knowledge-card {
padding: 20px 0 16px;
.head {
display: flex;
align-items: center;
.avatar {
width: 38px;
height: 38px;
margin-right: 10px;
}
.info {
width: 200px;
padding-right: 10px;
.name {
color: var(--cp-text2);
}
.dep {
color: var(--cp-tip);
font-size: 12px;
}
}
.btn {
padding: 0 12px;
border-color: var(--cp-primary);
color: var(--cp-primary);
height: 28px;
width: 72px;
}
}
.body {
.title {
font-size: 16px;
margin-top: 8px;
font-weight: normal;
}
.tag {
margin-top: 6px;
>span {
color: var(--cp-primary);
margin-right: 20px;
font-size: 12px;
}
}
.intro {
margin-top: 7px;
line-height: 2;
color: var(--cp-text3);
}
.imgs {
margin-top: 7px;
display: flex;
.van-image {
width: 106px;
height: 106px;
margin-right: 12px;
border-radius: 12px;
overflow: hidden;
&:last-child {
margin-right: 0;
}
}
&.large {
.van-image {
width: 185px;
height: 125px;
}
}
}
.logs {
margin-top: 10px;
>span {
color: var(--cp-tip);
margin-right: 16px;
font-size: 12px;
}
}
}
}
</style>

@ -1,76 +0,0 @@
<script setup lang="ts">
import KnowledgeCard from './KnowledgeCard.vue'
import {
ref
} from 'vue'
import type {
KnowledgeType,
KnowledgeList
} from '@/types/consult'
import {
getKnowledgePage
} from '@/api/consult'
//type()
const props = defineProps < {
type: KnowledgeType
} > ()
//
const list = ref < KnowledgeList > ([]);
//:true false()
const loading = ref(false);
//:falsw true
//1
//2
const finished = ref(false);
//
const params = {
type: props.type, //
current: 1, //
pageSize: 10 //
}
//
const onLoad = async () => {
//
// setTimeout ajax
const {
data
} = await getKnowledgePage(params)
//list
list.value.push(...data.rows)
//
loading.value = false;
//
// ?
//1list===total
//2current===pageTotal
if (list.value.length === data.total) {
//
finished.value = true;
} else {
//?+1
params.current++
}
};
</script>
<template>
<view class="knowledge-list">
<van-list v-model:loading="loading" :finished="finished" finished-text="" @load="onLoad">
<!-- 列表数据 -->
<knowledge-card v-for="item in list" :key="item.id" :item=item></knowledge-card>
</van-list>
</view>
</template>
<style lang="scss" scoped>
.knowledge-list {
padding: 0 15px;
}
</style>

@ -1,18 +1,23 @@
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-09 17:08:53
* @FilePath: \byhl-zt-app\src\config\env.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
/** 请求服务的环境配置 */
type ServiceEnv = Record<ServiceEnvType, ServiceEnvConfig>
const serviceEnv: ServiceEnv = {
export const serviceEnv: ServiceEnv = {
dev: {
url: 'http://127.0.0.1:8080',
},
test: {
url: 'http://192.168.22.148:8080',
url: 'http://172.18.0.225:8000',
},
prod: {
url: 'http://192.168.22.148:8080',
},
url: 'http://admin.ballcat.cn',
}
}
export const imgUrl = 'https://hccake-img.oss-cn-shanghai.aliyuncs.com/'
/**
*
* @param env

@ -1,3 +1,11 @@
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-09 15:36:51
* @FilePath: \byhl-zt-app\src\enums\common.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
export enum ENUM_STORAGE_KEY {
/** 用户token */
token = '__TOKEN__',
@ -5,4 +13,5 @@ export enum ENUM_STORAGE_KEY {
refreshToken = '__REFRESH_TOKEN__',
/** 用户信息 */
userInfo = '__USER_INFO__',
vitePasswordKey = '==BallCat-Auth=='
}

@ -1,72 +1,73 @@
{
"name": "",
"appid": "",
"description": "",
"versionName": "1.0.0",
"versionCode": "100",
"transformPx": false,
/* 5+App */
"app-plus": {
"usingComponents": true,
"nvueStyleCompiler": "uni-app",
"compilerVersion": 3,
"splashscreen": {
"alwaysShowBeforeRender": true,
"waiting": true,
"autoclose": true,
"delay": 0
"name" : "cmd",
"appid" : "__UNI__F6B11EE",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>"
]
},
/* ios */
"ios" : {},
/* SDK */
"sdkConfigs" : {}
}
},
/* */
"modules": {},
/* */
"distribute": {
/* android */
"android": {
"permissions": [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios */
"ios": {},
/* SDK */
"sdkConfigs": {}
}
},
/* */
"quickapp": {},
/* */
"mp-weixin": {
"appid": "",
"setting": {
"urlCheck": false
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true
},
"usingComponents": true
},
"mp-alipay": {
"usingComponents": true
},
"mp-baidu": {
"usingComponents": true
},
"mp-toutiao": {
"usingComponents": true
},
"uniStatistics": {
"enable": false
},
"vueVersion": "3"
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3"
}

@ -1,30 +1,23 @@
{
"pages": [ // pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index",
"style": {
// "navigationBarTitleText": "index",
// "enablePullDownRefresh": true,
// "onReachBottomDistance": 100,
"navigationStyle": "custom"
}
},
{
"path": "pages/login",
"style": {
"navigationBarTitleText": "登录"
}
},
},
{
"path": "pages/common/webview/index",
"path": "pages/index",
"style": {
"navigationBarTitleText": "浏览网页"
"navigationStyle": "custom",
"enablePullDownRefresh": true
}
},
{
"path": "pages/common/textview/index",
"path": "pages/common/assetsDetail/index",
"style": {
"navigationBarTitleText": "浏览文本"
"navigationBarTitleText": "线索详情",
"enablePullDownRefresh": true
}
},
{
@ -34,7 +27,7 @@
}
},
{
"path": "pages/work/index",
"path": "pages/assets/index",
"style": {
"navigationBarTitleText": "工作台"
}
@ -68,18 +61,6 @@
"style": {
"navigationBarTitleText": "应用设置"
}
},
{
"path": "pages/mine/help/index",
"style": {
"navigationBarTitleText": "常见问题"
}
},
{
"path": "pages/mine/about/index",
"style": {
"navigationBarTitleText": "关于我们"
}
}
],
"easycom": {
@ -96,14 +77,14 @@
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index",
"iconPath": "static/images/tabbar/home.png",
"selectedIconPath": "static/images/tabbar/home_.png",
"text": "首页"
}, {
"pagePath": "pages/work/index",
"iconPath": "static/images/tabbar/work.png",
"selectedIconPath": "static/images/tabbar/work_.png",
"text": "工作台"
"text": "客户列表"
}, {
"pagePath": "pages/assets/index",
"iconPath": "static/images/tabbar/home.png",
"selectedIconPath": "static/images/tabbar/home.png",
"text": "个人绩效"
}, {
"pagePath": "pages/mine/index",
"iconPath": "static/images/tabbar/mine.png",
@ -113,7 +94,7 @@
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "RuoYi",
"navigationBarTitleText": "呼叫中心",
"navigationBarBackgroundColor": "#FFFFFF"
}
}
}

@ -0,0 +1,148 @@
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { onLoad } from "@dcloudio/uni-app";
let addProp = ref(false)
const refForm = ref()
let addForm = reactive({
stageName: '',
record: [{val: ''}]
})
onLoad((option) => {
console.log("🚀 ~ file: index.vue:5 ~ onLoad ~ option:", option)
})
const cancellationFun = () => {
addProp.value = false
addForm.stageName = ''
addForm.record = [{val: ''}]
refForm.value.resetValidation()
}
const onRecordSubmit = () => {
}
const addRecord = () => {
addForm.record.push({val: ''})
console.log("🚀 ~ file: index.vue:23 ~ addRecord ~ addForm:", addForm)
}
</script>
<template>
<view>
<h2 class="title-doc-block text-base font-bold! py-20rpx px-32rpx text-c2 border-b-1 border-b-stone-300"><van-icon name="fire-o" color="#007aff" class="mr-10rpx"/>标签编辑</h2>
<view v-for="item in 2">
<h2 class="title-doc-block mt-32rpx py-24rpx px-32rpx fs-14">标签组1<text class="text-zinc-500">(单选)</text></h2>
<view class="px-32rpx flex flex-wrap">
<view v-for="it in 12" class="block-button mr-16rpx mb-16rpx" :class="{'tag-active': it == 3}">1</view>
</view>
</view>
<view class="flex justify-between border-b-1 border-b-stone-300 items-center px-32rpx py-20rpx">
<h2 class="title-doc-block text-base font-bold! text-c2"><van-icon name="fire-o" color="#007aff" class="mr-10rpx"/>跟进时间轴</h2>
<text class="block text-c7" @click="addProp = true">添加记录</text>
</view>
<view>
<van-steps direction="vertical" :active="88">
<van-step>
<view class="flex justify-between">
<van-tag type="primary" style="font-size: 14px;">标签</van-tag>
<text>2019-08-23</text>
</view>
<view class="card-block leading-5">
<text class="block">1w我是的一句话</text>
<text class="block">1w我是的二句话</text>
</view>
</van-step>
<van-step>
<view class="flex justify-between">
<van-tag type="primary" style="font-size: 14px;">标签</van-tag>
<text>2019-08-23</text>
</view>
<view class="card-block leading-5">
<text class="block">1w我是的一句话</text>
<text class="block">1w我是的二句话</text>
</view>
</van-step>
</van-steps>
</view>
</view>
<van-popup v-model:show="addProp" :style="{ width: '80%', borderRadius: '7px' }">
<view>
<text class="title-doc-block text-base font-bold! block text-center pt-30rpx mt-15rpx">添加记录</text>
<van-form ref="refForm" @submit="onRecordSubmit">
<van-cell-group inset>
<van-field
v-model="addForm.stageName"
name="阶段名"
label="阶段名"
placeholder="阶段名"
:rules="[{ required: true, message: '请填写阶段名' }]"
>
<template #button>
<van-icon name="add" color="#18CC73" @click="addRecord" />
</template>
</van-field>
<van-field
v-for="(item, index) in addForm.record"
v-model="item.val"
autosize
clearable
type="textarea"
maxlength="50"
show-word-limit
label="记录-1"
placeholder="记录"
>
</van-field>
</van-cell-group>
<div style="margin: 16px;" class="flex justify-around">
<van-button block class="w-30vw!" @click="cancellationFun">
取消
</van-button>
<van-button block type="primary" class="w-30vw!" native-type="submit">
提交
</van-button>
</div>
</van-form>
</view>
</van-popup>
</template>
<style scoped lang="scss">
page {
font-size: 14px;
}
::v-deep .van-field__label {
width: 100rpx;
}
.tag-active {
border: 1px solid #007aff!important;
background-color: #007aff;
color: #fff!important;
}
.title-doc-block {
margin: 0;
font-weight: 400;
line-height: 16px;
}
.block-button {
position: relative;
display: inline-block;
height: 54rpx;
text-align: center;
line-height: 54rpx;
color: $uni-text-color-placeholder;
border: 1px solid $uni-border-color;
padding: 0 20rpx;
border-radius: 4px;
}
.card-block {
border-radius: 4px;
padding: 15rpx;
border: 1px solid #ebeef5;
background-color: #fff;
overflow: hidden;
box-shadow: 0 2px 8px 0 rgba(0,0,0,.1);
margin-top: 15rpx;
color: $uni-text-color-placeholder;
}
</style>

@ -1,217 +1,189 @@
<!--
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-04 16:22:45
* @FilePath: \byhl-zt-app\src\pages\index.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<!--
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-04 14:04:15
* @FilePath: \byhl-zt-app\src\pages\index.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<script setup lang="ts">
import CpIcon from '@/components/CpIcon.vue'
import {
ref
} from 'vue'
import { parseTime } from '@/utils/index'
import { Navigate } from '@/utils/index'
import { Modal } from '@/plugins/Modal'
//
import KnowledgeList from '@/components/home/KnowledgeList.vue'
import type {
KnowledgeType
} from '@/types/consult'
import FollowDoctor from '@/components/home/FollowDoctor.vue'
import AssetsList from '@/components/home/AssetsList.vue'
import {
useUserStore
} from '@/store/user'
const store = useUserStore()
//
const active = ref < KnowledgeType > ('like')
type behavioraback = {
type: number
call: string
}
type behaviora = {
name: string
callback: () => behavioraback
}
let searchObj = reactive({
searchValue: '',
searchDate: ''
})
let searchEl: any = ref(null)
let pickerProp = ref<boolean>(false)
let behaviorProp = ref<boolean>(false)
let currentDate = ref<string[]>([])
let behavioractions = ref<behaviora[]>([])
let minDate = ref<Date>(new Date(2022, 0, 1))
let maxDate = ref<Date>(new Date(2026, 8, 1))
let actionShow = ref<boolean>(false)
const searchClick = () => {
searchEl.value.onLoad()
}
const moreExpand = () => {
actionShow.value = true
}
const onCancel = () => {
cancelPicker()
}
const initSerach = () => {
searchObj.searchDate = ''
}
const openDetail = (id: string) => {
Navigate.to('/pages/common/assetsDetail/index', { params: { id: id} })
}
const confirmClick =() => {
searchObj.searchDate = currentDate?.value[0] + "/" + currentDate?.value[1] + '/' + currentDate.value[2]
pickerProp.value = false
}
const cancelPicker = () => {
currentDate.value = []
pickerProp.value = false
}
const clickPlay = (call: string) => {
behavioractions.value = [
{ name: '拨打:' + call, callback: (): behavioraback => { return { type: 1, call: call } }},
{ name: '复制号码', callback: (): behavioraback => { return { type: 2, call: call } }}
]
behaviorProp.value = true
}
const onBehaviorSelect = (item: behaviora) => {
let params = item.callback()
if (params.type === 1) {
uni.makePhoneCall({
phoneNumber: params.call,
success: () => {
Modal.msg('呼叫成功~')
},
fail: (err) => {
console.log("🚀 ~ file: AssetsList.vue:80 ~ playCall ~ err:", err)
}
})
} else if (params.type === 2) {
uni.setClipboardData({
data: params.call,
success: function () {}
});
}
}
// //
// const active = ref < KnowledgeType > ('like')
</script>
<template>
<view class="home-page">
<!-- 头部 -->
<view class="home-header">
<view class="con">
<h1>{{store.userInfo?.mobile}}</h1>
<view class="search">
<CpIcon name="home-search" /> 搜一搜疾病/症状/医生/健康知识
</view>
</view>
</view>
<!-- 导航 -->
<view class="home-navs">
<van-row>
<van-col span="8">
<router-link to="/" class="nav">
<CpIcon name="home-doctor"></CpIcon>
<p class="title">问医生</p>
<p class="desc">按科室查问医生</p>
</router-link>
</van-col>
<van-col span="8">
<router-link to="/consult/fast" class="nav">
<CpIcon name="home-graphic"></CpIcon>
<p class="title">极速问诊</p>
<p class="desc">20s医生极速回复</p>
</router-link>
</van-col>
<van-col span="8">
<router-link to="/" class="nav">
<CpIcon name="home-prescribe"></CpIcon>
<p class="title">开药门诊</p>
<p class="desc">线上买药更方便</p>
</router-link>
</van-col>
</van-row>
<van-row>
<van-col span="6">
<router-link to="/" class="nav min">
<CpIcon name="home-order"></CpIcon>
<p class="title">药品订单</p>
</router-link>
</van-col>
<van-col span="6">
<router-link to="/" class="nav min">
<CpIcon name="home-docs"></CpIcon>
<p class="title">健康档案</p>
</router-link>
</van-col>
<van-col span="6">
<router-link to="/" class="nav min">
<CpIcon name="home-rp"></CpIcon>
<p class="title">我的处方</p>
</router-link>
</van-col>
<van-col span="6">
<router-link to="/" class="nav min">
<CpIcon name="home-find"></CpIcon>
<p class="title">疾病查询</p>
</router-link>
</van-col>
</van-row>
<view class="home-page mb-100rpx">
<!-- 头部-seach -->
<view class="home-header px-30rpx">
<view class="text-center text-white font-bold text-base py-15rpx">客户列表</view>
<van-sticky>
<van-search
v-model="searchObj.searchValue"
show-action
shape="round"
background="#fff"
placeholder="请输入搜索关键词"
>
<template #action>
<view class="flex items-center">
<view class="text-primary van-haptics-feedback mr-14rpx" @click.stop="searchClick">搜索</view>
<view @click.stop="moreExpand"><uni-icons type="bottom"></uni-icons> </view>
</view>
</template>
</van-search>
</van-sticky>
</view>
<!-- 轮播图 -->
<view class="home-banner">
<van-swipe indicator-color="#fff">
<van-swipe-item>
<img src="@/static/images/ad.png" alt="" />
</van-swipe-item>
<van-swipe-item>
<img src="@/static/images/ad.png" alt="" />
</van-swipe-item>
</van-swipe>
</view>
<!-- 4知识列表:关注推荐减脂饮食 -->
<van-tabs shrink sticky v-model:active="active">
<van-tab name="like" title="关注">
<!-- 关注医生列表 -->
<FollowDoctor></FollowDoctor>
<!-- 知识列表 -->
<KnowledgeList type="like"></KnowledgeList>
</van-tab>
<van-tab name="recommend" title="推荐">
<KnowledgeList type="recommend"></KnowledgeList>
</van-tab>
<van-tab name="fatReduction" title="减脂">
<KnowledgeList type="fatReduction"></KnowledgeList>
</van-tab>
<van-tab name="food" title="饮食">
<KnowledgeList type="food"></KnowledgeList>
</van-tab>
</van-tabs>
<view class="px-30rpx assets-list">
<AssetsList ref="searchEl" :searchVal="searchObj.searchValue" @clickDetail="openDetail" @toPlay="clickPlay" />
</view>
<van-action-sheet v-model:show="actionShow" title="" cancel-text="" :round="false" :closeable="false" close-on-click-action @cancel="onCancel">
<view class="content">
<view v-show="!pickerProp">
<van-cell title="日期" is-link :value="searchObj.searchDate" @click.stop="pickerProp = true">
<template #right-icon>
<view class="flex items-center">
<van-icon v-if="searchObj.searchDate != ''" name="close" class="mr-6rpx ml-6rpx active:text-c6!" @click.stop="searchObj.searchDate = ''" />
<van-icon name="arrow" />
</view>
</template>
</van-cell>
<view class="flex justify-around my-20rpx">
<van-button type="default" class="w-40vw" @click="initSerach"></van-button>
<van-button type="primary" class="w-40vw">搜索</van-button>
</view>
</view>
<van-date-picker
v-model="currentDate"
v-show="pickerProp"
title="选择日期"
:min-date="minDate"
:max-date="maxDate"
@confirm="confirmClick"
@cancel="cancelPicker"
/>
</view>
</van-action-sheet>
<van-action-sheet
v-model:show="behaviorProp"
:actions="behavioractions"
@select="onBehaviorSelect"
cancel-text="取消"
description="客户操作"
close-on-click-action
/>
</view>
</template>
<style lang="scss" scoped>
page {
background-color: $uni-bg-color-grey;
}
::v-deep .van-search {
padding: 0;
}
::v-deep .van-search__content {
background: #fff
}
::v-deep .van-search__action:active {
background-color: initial;
}
.home-page {
padding-bottom: 50px;
}
.home-header {
height: 100px;
position: relative;
&::before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 90px;
background: linear-gradient(180deg, rgba(62, 206, 197, 0.85), #26bcc6);
border-bottom-left-radius: 150px 20px;
border-bottom-right-radius: 150px 20px;
}
.con {
position: relative;
padding: 0 15px;
>h1 {
font-size: 18px;
color: #fff;
font-weight: normal;
padding: 20px 0;
line-height: 1;
padding-left: 5px;
}
.search {
height: 40px;
border-radius: 20px;
box-shadow: 0px 15px 22px -7px rgba(224, 236, 250, 0.8);
background-color: #fff;
display: flex;
align-items: center;
padding: 0 20px;
color: var(--cp-dark);
font-size: 13px;
.CpIcon {
font-size: 16px;
margin-right: 5px;
}
}
}
}
.home-navs {
padding: 10px 15px 0 15px;
.nav {
display: flex;
flex-direction: column;
align-items: center;
padding: 10px 0;
.CpIcon {
font-size: 48px;
}
.title {
font-weight: 500;
margin-top: 5px;
color: var(--cp-text1);
}
.desc {
font-size: 11px;
color: var(--cp-tag);
margin-top: 2px;
}
&.min {
.CpIcon {
font-size: 31px;
}
.title {
font-size: 13px;
color: var(--cp-text2);
font-weight: normal;
}
}
}
}
.home-banner {
padding: 10px 15px;
height: 100px;
img {
width: 100%;
height: 100%;
}
}
</style>
.assets-list {
margin-top: -60rpx;
}
.home-header {
height: 220rpx;
background-image: linear-gradient(to bottom , #18B4B3, $uni-bg-color-grey);
}
</style>

@ -1,20 +1,30 @@
<!--
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-09 16:13:58
* @FilePath: \byhl-zt-app\src\pages\login.vue
-->
<script setup lang="ts">
import {
loginAPI
} from '@/api/user'
import {
useUserStore
} from '@/store/user'
import {
Modal
} from '@/plugins/Modal'
import {
Navigate
} from '@/utils'
import {
showSuccessToast
} from 'vant'
import { loginAPI } from '@/api/user'
import { useUserStore } from '@/store/user'
import { Modal } from '@/plugins/Modal'
import { Navigate, passEncrypt } from '@/utils'
import { showSuccessToast } from 'vant'
import { LoginResult } from '@/types/user'
import { SliderCaptcha as LoginCaptcha } from '@/components/Captcha/index'
import type { LoginFormInstance } from '@/components/Captcha/types'
import { accountLogin } from '@/api/login'
const store = useUserStore()
//
const enableLoginCaptcha = true
//
const loginLoading = ref(false)
//
const isLoginError = ref(false)
//
const loginFormRef = ref<LoginFormInstance>()
const loginCaptchaRef = ref()
const loginForm = reactive({
username: '',
password: '',
@ -36,7 +46,6 @@
// return
// }
const res = await loginAPI(loginForm.mobile, loginForm.password)
// localStorage.setItem('doctor-h5', JSON.stringify(res.data))
store.saveUser(res.data)
showSuccessToast('登录成功')
Navigate.reLaunch('/pages/index')
@ -50,19 +59,55 @@
//
const handleLogin = async () => {
if (loginForm.mobile === '') {
Modal.msgError('请输入您的账号')
Modal.msg('请输入您的账号')
} else if (loginForm.password === '') {
Modal.msgError('请输入您的密码')
}
// else if (loginForm.code === '' && captchaEnabled.value) {
// Modal.msgError('')
// }
else {
// Modal.loading('...')
pwdLogin()
Modal.msg('请输入您的密码')
} else {
enableLoginCaptcha ? loginCaptchaRef.value?.show() : handleSubmit()
// pwdLogin()
}
}
const handleSubmit = (captchaId? :string) => {
loginLoading.value = true
return new Promise((resolve, reject) => {
doLogin(captchaId).then((res: any) => {
console.log("🚀 ~ file: login.vue:75 ~ doLogin ~ res:", res)
isLoginError.value = false
setStore(res)
Navigate.reLaunch('/pages/index')
})
.catch((err: { response: any }) => {
console.log("🚀 ~ file: login.vue:80 ~ returnnewPromise ~ err:", err)
isLoginError.value = true
Modal.msg(((err.response || {}).data || {}).error || '请求出现错误,请稍后再试')
}).finally(() => {
loginLoading.value = false
})
})
}
const doLogin = (captchaId?: string) => {
return accountLogin({
grant_type: 'password',
username: loginForm.mobile,
password: passEncrypt(loginForm.password), //
captchaId // id
})
}
/** 存储登录信息 */
const setStore = (res: LoginResult) => {
const userStore = useUserStore()
// token
userStore.accessToken = res.access_token
//
const info = res.info
const roleCodes = res.attributes?.roleCodes || []
const permissions = res.attributes?.permissions || []
userStore.saveUser({
...info,
roleCodes,
permissions
})
}
//
const handleUserAgreement = () => {
Navigate.to('/pages/common/webview/index')
@ -72,8 +117,6 @@
Navigate.to('/pages/common/webview/index')
}
onLoad(async () => {
// getCode()
})
@ -84,10 +127,10 @@
<template>
<view class="normal-login-container">
<view class="logo-content align-center justify-center flex">
<!-- <image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix">
<!-- <image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix">
</image> -->
<text class="title">
若依移动端登录
橘猫呼叫系统
</text>
</view>
<view class="login-form-content">
@ -105,9 +148,9 @@
<image :src="codeUrl" class="login-code-img" @click="getCode" />
</view> -->
<view class="action-btn">
<button class="login-btn text-white bg-blue " @click="handleLogin">
<van-button :loading="loginLoading" type="primary" class="w80vw mt-6vh!" @click="handleLogin">
登录
</button>
</van-button>
</view>
</view>
@ -122,6 +165,8 @@
隐私协议
</text>
</view>
<!-- 登陆验证码 -->
<login-captcha v-if="enableLoginCaptcha" ref="loginCaptchaRef" @success="handleSubmit" />
</view>
</template>
@ -155,7 +200,7 @@
.input-item {
margin: 20px auto;
background-color: #f5f6f7;
background-color: $uni-bg-color-grey;
height: 45px;
line-height: 45px;
border-radius: 20px;
@ -177,11 +222,6 @@
}
.login-btn {
margin-top: 40px;
height: 45px;
}
.xieyi {
color: #333;
margin-top: 20px;
@ -196,4 +236,4 @@
.login-code-img {
height: 45px;
}
</style>
</style>

@ -1,5 +0,0 @@
<script setup lang="ts">
</script>
<template>
<view>mine</view>
</template>

@ -1,5 +0,0 @@
<script setup lang="ts">
</script>
<template>
<view>mine</view>
</template>

@ -1,144 +1,57 @@
<!--
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-09 17:09:36
* @FilePath: \byhl-zt-app\src\pages\mine\index.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<script setup lang="ts">
import {Navigate} from "@/utils";
const windowHeight=ref(0)
const avatar=ref(true)
const name=ref('123')
const handleToAvatar=()=>{
}
const handleToLogin=()=>{
}
const handleToInfo=()=>{
Navigate.to('/pages/mine/info/index')
import { useUserStore } from '@/store/user'
import { Modal } from '@/plugins/Modal'
import { imgUrl } from '@/config/env.ts'
const avatar = imgUrl
const { userInfo } = useUserStore()
const handleToLogin = async () => {
let isConfirm = await Modal.confirm('确认退出登录吗')
if (isConfirm) {
Navigate.to('/pages/login')
}
}
onLoad (() => {
// console.log('llllllll=', avatar + userInfo?.avatar)
})
// const handleToInfo = () => {
// Navigate.to('/pages/mine/info/index')
// }
</script>
<template>
<view class="mine-container" :style="{height: `${windowHeight}px`}">
<!--顶部个人信息栏-->
<view class="header-section">
<view class="flex justify-between">
<view class="flex items-center">
<view v-if="!avatar" class="cu-avatar rounded-1/2 bg-white ">
<view class="iconfont icon-people text-gray icon"></view>
</view>
<image v-if="avatar" @click="handleToAvatar" src="/static/images/profile.jpg" class="cu-avatar !w-100rpx !h-100rpx rounded-1/2" mode="widthFix">
</image>
<view v-if="!name" @click="handleToLogin" class="login-tip">
点击登录
</view>
<view v-if="name" @click="handleToInfo" class="user-info">
<view class="u_title">
用户名{{ name }}
</view>
</view>
</view>
<view @click="handleToInfo" class="flex items-center">
<text>个人信息</text>
<view class="iconfont icon-right"></view>
</view>
</view>
</view>
<view class="content-section">
<view class="mine-actions grid grid-cols-4 text-center">
<view class="action-item" >
<view class="icon"></view>
<text class="text">交流群</text>
</view>
<view class="action-item" >
<view class="icon"></view>
<text class="text">在线客服</text>
</view>
<view class="action-item" >
<view class="icon"></view>
<text class="text">反馈社区</text>
</view>
<view class="action-item" >
<view class="icon"></view>
<text class="text">点赞我们</text>
</view>
</view>
<uni-list class="m-4 rounded-2xl">
<navigator url="/pages/mine/info/edit" >
<uni-list-item :show-extra-icon="true" showArrow title="编辑资料" />
</navigator>
<uni-list-item :show-extra-icon="true" showArrow title="常见问题" />
<uni-list-item :show-extra-icon="true" showArrow title="关于我们" />
<navigator url="/pages/mine/setting/index" >
<uni-list-item :show-extra-icon="true" showArrow title="应用设置" />
</navigator>
</uni-list>
<view class="mine-container m-30rpx bg-white">
<view class="pt-150rpx">
<image :src="avatar + '/' + userInfo?.avatar" class="w-160rpx h-160rpx border block m-auto rounded-full" />
</view>
<van-cell-group>
<van-cell title="账号名称" :value="userInfo?.nickname" />
<van-cell title="组" value="未知" />
<van-cell title="软件版本" value="1.0.1" />
</van-cell-group>
</view>
<van-button type="primary" class="w-90vw block! m-auto! fixed! button" @click="handleToLogin">退</van-button>
</template>
<style scoped lang="scss">
page {
background-color: #f5f6f7;
background-color: $uni-bg-color-grey;
}
.mine-container {
width: 100%;
height: 100%;
.header-section {
padding: 15px 15px 45px 15px;
background-color: #3c96f3;
color: white;
.login-tip {
font-size: 18px;
margin-left: 10px;
}
.cu-avatar {
border: 2px solid #eaeaea;
.icon {
font-size: 40px;
}
}
.user-info {
margin-left: 15px;
.u_title {
font-size: 18px;
line-height: 30px;
}
}
}
.content-section {
position: relative;
top: -50px;
.mine-actions {
margin: 15px 15px;
padding: 20px 0px;
border-radius: 8px;
background-color: white;
.action-item {
.icon {
font-size: 28px;
}
.text {
display: block;
font-size: 13px;
margin: 8px 0px;
}
}
}
}
}
.button {
bottom: 220rpx;
left: 0;
right: 0;
}
</style>

@ -1,3 +1,11 @@
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-02 15:40:45
* @FilePath: \byhl-zt-app\src\plugins\Modal.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
export class Modal {
// 消息提示
static msg(content: string) {
@ -33,10 +41,10 @@ export class Modal {
})
}
// 确认窗体
static confirm(content: string) {
static confirm(content: string, title: string = '系统提示') {
return new Promise((resolve) => {
uni.showModal({
title: '系统提示',
title: title,
content,
cancelText: '取消',
confirmText: '确定',

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="1361px" height="609px" viewBox="0 0 1361 609" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Group 21</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Ant-Design-Pro-3.0" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="账户密码登录-校验" transform="translate(-79.000000, -82.000000)">
<g id="Group-21" transform="translate(77.000000, 73.000000)">
<g id="Group-18" opacity="0.8" transform="translate(74.901416, 569.699158) rotate(-7.000000) translate(-74.901416, -569.699158) translate(4.901416, 525.199158)">
<ellipse id="Oval-11" fill="#CFDAE6" opacity="0.25" cx="63.5748792" cy="32.468367" rx="21.7830479" ry="21.766008"></ellipse>
<ellipse id="Oval-3" fill="#CFDAE6" opacity="0.599999964" cx="5.98746479" cy="13.8668601" rx="5.2173913" ry="5.21330997"></ellipse>
<path d="M38.1354514,88.3520215 C43.8984227,88.3520215 48.570234,83.6838647 48.570234,77.9254015 C48.570234,72.1669383 43.8984227,67.4987816 38.1354514,67.4987816 C32.3724801,67.4987816 27.7006688,72.1669383 27.7006688,77.9254015 C27.7006688,83.6838647 32.3724801,88.3520215 38.1354514,88.3520215 Z" id="Oval-3-Copy" fill="#CFDAE6" opacity="0.45"></path>
<path d="M64.2775582,33.1704963 L119.185836,16.5654915" id="Path-12" stroke="#CFDAE6" stroke-width="1.73913043" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M42.1431708,26.5002681 L7.71190162,14.5640702" id="Path-16" stroke="#E0B4B7" stroke-width="0.702678964" opacity="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
<path d="M63.9262187,33.521561 L43.6721326,69.3250951" id="Path-15" stroke="#BACAD9" stroke-width="0.702678964" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="1.405357899873153,2.108036953469981"></path>
<g id="Group-17" transform="translate(126.850922, 13.543654) rotate(30.000000) translate(-126.850922, -13.543654) translate(117.285705, 4.381889)" fill="#CFDAE6">
<ellipse id="Oval-4" opacity="0.45" cx="9.13482653" cy="9.12768076" rx="9.13482653" ry="9.12768076"></ellipse>
<path d="M18.2696531,18.2553615 C18.2696531,13.2142826 14.1798519,9.12768076 9.13482653,9.12768076 C4.08980114,9.12768076 0,13.2142826 0,18.2553615 L18.2696531,18.2553615 Z" id="Oval-4" transform="translate(9.134827, 13.691521) scale(-1, -1) translate(-9.134827, -13.691521) "></path>
</g>
</g>
<g id="Group-14" transform="translate(216.294700, 123.725600) rotate(-5.000000) translate(-216.294700, -123.725600) translate(106.294700, 35.225600)">
<ellipse id="Oval-2" fill="#CFDAE6" opacity="0.25" cx="29.1176471" cy="29.1402439" rx="29.1176471" ry="29.1402439"></ellipse>
<ellipse id="Oval-2" fill="#CFDAE6" opacity="0.3" cx="29.1176471" cy="29.1402439" rx="21.5686275" ry="21.5853659"></ellipse>
<ellipse id="Oval-2-Copy" stroke="#CFDAE6" opacity="0.4" cx="179.019608" cy="138.146341" rx="23.7254902" ry="23.7439024"></ellipse>
<ellipse id="Oval-2" fill="#BACAD9" opacity="0.5" cx="29.1176471" cy="29.1402439" rx="10.7843137" ry="10.7926829"></ellipse>
<path d="M29.1176471,39.9329268 L29.1176471,18.347561 C23.1616351,18.347561 18.3333333,23.1796097 18.3333333,29.1402439 C18.3333333,35.1008781 23.1616351,39.9329268 29.1176471,39.9329268 Z" id="Oval-2" fill="#BACAD9"></path>
<g id="Group-9" opacity="0.45" transform="translate(172.000000, 131.000000)" fill="#E6A1A6">
<ellipse id="Oval-2-Copy-2" cx="7.01960784" cy="7.14634146" rx="6.47058824" ry="6.47560976"></ellipse>
<path d="M0.549019608,13.6219512 C4.12262681,13.6219512 7.01960784,10.722722 7.01960784,7.14634146 C7.01960784,3.56996095 4.12262681,0.670731707 0.549019608,0.670731707 L0.549019608,13.6219512 Z" id="Oval-2-Copy-2" transform="translate(3.784314, 7.146341) scale(-1, 1) translate(-3.784314, -7.146341) "></path>
</g>
<ellipse id="Oval-10" fill="#CFDAE6" cx="218.382353" cy="138.685976" rx="1.61764706" ry="1.61890244"></ellipse>
<ellipse id="Oval-10-Copy-2" fill="#E0B4B7" opacity="0.35" cx="179.558824" cy="175.381098" rx="1.61764706" ry="1.61890244"></ellipse>
<ellipse id="Oval-10-Copy" fill="#E0B4B7" opacity="0.35" cx="180.098039" cy="102.530488" rx="2.15686275" ry="2.15853659"></ellipse>
<path d="M28.9985381,29.9671598 L171.151018,132.876024" id="Path-11" stroke="#CFDAE6" opacity="0.8"></path>
</g>
<g id="Group-10" opacity="0.799999952" transform="translate(1054.100635, 36.659317) rotate(-11.000000) translate(-1054.100635, -36.659317) translate(1026.600635, 4.659317)">
<ellipse id="Oval-7" stroke="#CFDAE6" stroke-width="0.941176471" cx="43.8135593" cy="32" rx="11.1864407" ry="11.2941176"></ellipse>
<g id="Group-12" transform="translate(34.596774, 23.111111)" fill="#BACAD9">
<ellipse id="Oval-7" opacity="0.45" cx="9.18534718" cy="8.88888889" rx="8.47457627" ry="8.55614973"></ellipse>
<path d="M9.18534718,17.4450386 C13.8657264,17.4450386 17.6599235,13.6143199 17.6599235,8.88888889 C17.6599235,4.16345787 13.8657264,0.332739156 9.18534718,0.332739156 L9.18534718,17.4450386 Z" id="Oval-7"></path>
</g>
<path d="M34.6597385,24.809694 L5.71666084,4.76878945" id="Path-2" stroke="#CFDAE6" stroke-width="0.941176471"></path>
<ellipse id="Oval" stroke="#CFDAE6" stroke-width="0.941176471" cx="3.26271186" cy="3.29411765" rx="3.26271186" ry="3.29411765"></ellipse>
<ellipse id="Oval-Copy" fill="#F7E1AD" cx="2.79661017" cy="61.1764706" rx="2.79661017" ry="2.82352941"></ellipse>
<path d="M34.6312443,39.2922712 L5.06366663,59.785082" id="Path-10" stroke="#CFDAE6" stroke-width="0.941176471"></path>
</g>
<g id="Group-19" opacity="0.33" transform="translate(1282.537219, 446.502867) rotate(-10.000000) translate(-1282.537219, -446.502867) translate(1142.537219, 327.502867)">
<g id="Group-17" transform="translate(141.333539, 104.502742) rotate(275.000000) translate(-141.333539, -104.502742) translate(129.333539, 92.502742)" fill="#BACAD9">
<circle id="Oval-4" opacity="0.45" cx="11.6666667" cy="11.6666667" r="11.6666667"></circle>
<path d="M23.3333333,23.3333333 C23.3333333,16.8900113 18.1099887,11.6666667 11.6666667,11.6666667 C5.22334459,11.6666667 0,16.8900113 0,23.3333333 L23.3333333,23.3333333 Z" id="Oval-4" transform="translate(11.666667, 17.500000) scale(-1, -1) translate(-11.666667, -17.500000) "></path>
</g>
<circle id="Oval-5-Copy-6" fill="#CFDAE6" cx="201.833333" cy="87.5" r="5.83333333"></circle>
<path d="M143.5,88.8126685 L155.070501,17.6038544" id="Path-17" stroke="#BACAD9" stroke-width="1.16666667"></path>
<path d="M17.5,37.3333333 L127.466252,97.6449735" id="Path-18" stroke="#BACAD9" stroke-width="1.16666667"></path>
<polyline id="Path-19" stroke="#CFDAE6" stroke-width="1.16666667" points="143.902597 120.302281 174.935455 231.571342 38.5 147.510847 126.366941 110.833333"></polyline>
<path d="M159.833333,99.7453842 L195.416667,89.25" id="Path-20" stroke="#E0B4B7" stroke-width="1.16666667" opacity="0.6"></path>
<path d="M205.333333,82.1372105 L238.719406,36.1666667" id="Path-24" stroke="#BACAD9" stroke-width="1.16666667"></path>
<path d="M266.723424,132.231988 L207.083333,90.4166667" id="Path-25" stroke="#CFDAE6" stroke-width="1.16666667"></path>
<circle id="Oval-5" fill="#C1D1E0" cx="156.916667" cy="8.75" r="8.75"></circle>
<circle id="Oval-5-Copy-3" fill="#C1D1E0" cx="39.0833333" cy="148.75" r="5.25"></circle>
<circle id="Oval-5-Copy-2" fill-opacity="0.6" fill="#D1DEED" cx="8.75" cy="33.25" r="8.75"></circle>
<circle id="Oval-5-Copy-4" fill-opacity="0.6" fill="#D1DEED" cx="243.833333" cy="30.3333333" r="5.83333333"></circle>
<circle id="Oval-5-Copy-5" fill="#E0B4B7" cx="175.583333" cy="232.75" r="5.25"></circle>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.7 KiB

@ -0,0 +1,17 @@
@font-face {
font-family: "iconfont"; /* Project id 2761882 */
src: url('./iconfont.ttf') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-dianhua:before {
content: "\e6a9";
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -1,24 +1,38 @@
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-09 16:16:28
* @FilePath: \byhl-zt-app\src\store\user.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import type { User } from '@/types/user'
import { setToken } from '@/utils/Storage'
import { defineStore } from 'pinia'
import { ref } from 'vue'
export interface UserInfo extends User {
roleCodes: string[]
permissions: string[]
}
export const useUserStore = defineStore(
'user', // 是唯一标识也是本地存储的key值
() => {
// 声明变量
// 声明变量
const userInfo = ref<User>()
let accessToken = ref()
// 设置用户信息,登录后使用
const saveUser = (u: User) => {
const saveUser = (u: UserInfo) => {
userInfo.value = u
console.log(userInfo.value, 'userInfo.value')
}
// 删除用户信息,退出登录后使用
const delUser = () => {
userInfo.value = undefined
}
return { userInfo, saveUser, delUser }
const setToken = (token: string) => {
accessToken.value = token
setToken(token)
}
return { userInfo, saveUser, delUser, accessToken }
},
{ persist: true }
)

@ -66,3 +66,22 @@ ol {
#nprogress .bar {
background-color: var(--cp-primary) !important;
}
.text-primary {
color: $uni-color-primary;
}
//
.button-primary {
background: $uni-color-primary;
}
.u-flex {
display: flex;
align-items: center;
}
.inline-block {
display: inline-block;
}
.fs-14 {
font-size: 14px;
}
//

@ -1,47 +1,34 @@
// 文章类型
export type KnowledgeType = 'like' | 'recommend' | 'fatReduction' | 'food'
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-03 13:44:11
* @FilePath: \byhl-zt-app\src\types\consult.d.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
// // 文章类型
// export type KnowledgeType = 'like' | 'recommend' | 'fatReduction' | 'food'
//通用的泛型工具
export type PageData<T> = {
pageTital: number
total: number
rows: T
}
// 1、健康知识列表:文章信息类型
export type Knowledge = {
id: string
/** 标题 */
title: string
/** 封面[] */
coverUrl: string[]
/** 标签[] */
topics: string[]
/** 收藏数 */
collectionNumber: number
/** 评论数 */
commentNumber: number
/** 医生名称 */
creatorName: string
/** 医生头像 */
creatorAvatar: string
/** 医生医院 */
creatorHospatalName: string
/** 关注文章 */
likeFlag: 0 | 1
/** 内容 */
content: string
/** 医生科室 */
creatorDep: string
/** 医生职称 */
creatorTitles: string
/** 医生ID */
creatorId: string
// 1、资源对象
export type AssetsObj = {
id: number
name: string
state: number
lastTime: number
call: string
tag: string[]
}
// 文章列表
export type KnowledgeList = Knowledge[]
// 资源列表
export type AssetsList = AssetsObj[]
// 文章列表带分页 api接口data指定类型
export type KnowledgePage = PageData<KnowledgeList>
// 分页 api接口data指定类型
export type AssetsPage = PageData<AssetsList>
// {
// pageTotal: number // 总页数
// total: number // 总条数
@ -59,12 +46,11 @@ export type KnowledgePage = PageData<KnowledgeList>
export type PageParams = {
current: number // 当前页
pageSize: number // 一页多少条
searchVal?: string | number
}
// 文章列表查询参数
export type KnowledgeParams = PageParams & {
type: KnowledgeType
}
export type KnowledgeParams = PageParams
// 医生卡片
export type Doctor = {
@ -87,8 +73,4 @@ export type DoctorList = Doctor[]
// 医生分页 api返回数据data类型
export type DoctorPage = PageData<DoctorList>
// {
// pageTotal: number
// total: number
// rows: DoctorList
// }

@ -1,26 +1,20 @@
export interface User {
/**
*
*/
account?: string
/**
*
*/
userId: number
username: string
type: number
organizationId: number
nickname: string
avatar?: string
/**
* id
*/
id?: string
/**
*
*/
mobile?: string
/**
* refreshToken
*/
refreshToken: string
/**
* token
*/
token: string
}
export interface LoginResult {
access_token: string
attributes: {
permissions: string[]
roleCodes: string[]
}
expires_in: number
info: User
refresh_token: string
scope: string
token_type: string
}

@ -1,10 +1,9 @@
/**
*
* - dev:
* - test:
* - prod:
*/
type ServiceEnvType = 'dev' | 'test' | 'prod'
type ServiceEnvType = 'dev' | 'prod'
/** 后台服务的环境配置 */
interface ServiceEnvConfig {

@ -26,10 +26,11 @@ $uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
$uni-text-color-title: #969799;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-grey:#f5f6f7;
$uni-bg-color-hover:#f1f1f1;//
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//

@ -1,8 +1,16 @@
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-09 16:14:08
* @FilePath: \byhl-zt-app\src\utils\Storage.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import Storage from '@/modal/useStorage'
export const tokenKey = 'token'
export function getToken() {
return Storage.get(tokenKey) || 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImNhMWFjMzNiLTM2MDQtNDFiMi04OWU0LWI5NTQ0YzNiOTgzZiJ9.aZ7XpTl8O4f89N-nzmEexhuUVbvUIjapjpQKjsqBK6rJAO6HTWNkElxcTwTb_WVOXtKNv_gawCH0V7vH-3gE8g'
return Storage.get(tokenKey)
}
export function setToken(token: string) {
Storage.set(tokenKey, token)

@ -1,3 +1,13 @@
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-09 15:38:40
* @FilePath: \byhl-zt-app\src\utils\index.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import CryptoJS from 'crypto-js/index'
import { ENUM_STORAGE_KEY } from '@/enums/common'
interface NavigateOptions {
params?: object
}
@ -37,11 +47,9 @@ export class Navigate {
uni.navigateTo({
url: url + resolveParams(params),
success(res) {
console.log(res)
success && success(res)
},
fail(err) {
console.log(err)
fail && fail(err)
},
})
@ -49,7 +57,7 @@ export class Navigate {
uni.navigateTo({url})
}
}
static redirect(url:string,options?: Omit<NavigateToOptions,'url'>) {
static redirect(url:string,options?: Omit<NavigateToOptions,'url'>) {
if(options!==undefined){
const { params, success } = options
uni.redirectTo({
@ -115,3 +123,65 @@ export function resolveParams(params: AnyObject | undefined) {
return ''
}
}
// 生成随机字符串
export const getRandomAlphaNum = (len: number) => {
let rdmString = ''
for (; rdmString.length < len; rdmString += Math.random().toString(36).substring(2));
return rdmString.substring(0, len)
}
export enum FormatsEnums {
YMD = 'Y-m-d',
YMDHIS = 'Y-m-d H:i:s',
_YMD = 'Y年m月d日',
_YMDHIS = 'Y年m月d日 H时i分'
}
export const parseTime = function (
timestamp: number,
formats: FormatsEnums = FormatsEnums.YMD
): string {
// formats格式包括
// 1. Y-m-d
// 2. Y-m-d H:i:s
// 3. Y年m月d日
// 4. Y年m月d日 H时i分
formats = formats || 'Y-m-d'
const zero = function (value: number): string | number {
if (value < 10) {
return '0' + value
}
return value
}
const myDate = timestamp ? new Date(timestamp) : new Date()
const year = myDate.getFullYear()
const month = zero(myDate.getMonth() + 1)
const day = zero(myDate.getDate())
const hour = zero(myDate.getHours())
const minite = zero(myDate.getMinutes())
const second = zero(myDate.getSeconds())
return formats.replace(/Y|m|d|H|i|s/gi, function (matches: string): any {
return {
Y: year,
m: month,
d: day,
H: hour,
i: minite,
s: second
}[matches]
})
}
export const passEncrypt = (pass: string) => {
// 密码加密
const key = CryptoJS.enc.Utf8.parse(ENUM_STORAGE_KEY.vitePasswordKey)
return CryptoJS.AES.encrypt(pass, key, {
iv: key,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString()
}

@ -1,19 +1,28 @@
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-09 15:57:54
* @FilePath: \byhl-zt-app\src\utils\request.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import axios from 'axios'
import { useUserStore } from '@/store/user'
export const baseURL = 'https://consult-api.itheima.net/'
const request = axios.create({
export const baseURL = import.meta.env.VITE_APP_BASE_API
const request = axios.create({
// TODO 1. 基础地址,超时时间
baseURL,
timeout: 5000
})
request.interceptors.request.use(
function(config) {
function(config) {
const store = useUserStore()
if (store.userInfo?.token && config.headers) {
config.headers['Authorization'] = `Bearer ${store.userInfo?.token}` // config.headers.Authorization也是可以的
if (store.accessToken && config.headers) {
config.headers['Authorization'] = `Bearer ${store.accessToken}` // config.headers.Authorization也是可以的
}
config.headers['Content-Type'] = 'application/json'
return config
},
function(err) {

@ -1,3 +1,11 @@
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-04 11:00:41
* @FilePath: \byhl-zt-app\unocss.config.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import presetWeapp from 'unocss-preset-weapp'
export default {
presets: [
@ -8,10 +16,15 @@ export default {
{
'border-base': 'border border-[#eee]',
'flex-center': 'flex justify-center items-center',
'text-15': 'font-size: 15px',
'text-c1': 'text-[#181818]',
'text-c2': 'text-[#333333]',
'text-c3': 'text-[#B2B2B2]',
'text-c4': 'text-[#CCCCCC]',
'text-c5': 'text-[#999999]',
'text-c6': 'text-[#18CC73]',
'text-c7': 'text-[#007aff]',
'text-c8': 'text-[#52C1F5]',
'bg': 'bg-[#f6f7fb]',
},
],

@ -1,3 +1,11 @@
/*
* @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @Date: 2023-07-28 16:10:52
* @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
* @LastEditTime: 2023-08-08 18:20:30
* @FilePath: \byhl-zt-app\vite.config.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import path from 'path'
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
@ -8,9 +16,21 @@ import vue from '@vitejs/plugin-vue';
import Components from 'unplugin-vue-components/vite';
import { VantResolver } from 'unplugin-vue-components/resolvers';
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
// const VITE_APP_SERVER_URL: string = loadEnv(mode, process.cwd()).VITE_APP_SERVER_URL;
// https://vitejs.dev/config/
export default defineConfig({
server: {
open: true,
cors: true,
proxy: {
"^/api": { //服务器接口路径地址,根据路径设置
target: 'http://172.18.0.225:8000', //你的服务器地址
changeOrigin: true, // 允许跨域
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
resolve: {
alias: {
'~/': `${path.resolve(__dirname, 'src')}/`,
@ -22,8 +42,9 @@ export default defineConfig({
resolvers: [VantResolver()],
}),
createSvgIconsPlugin({
//指定图标文件夹,绝对路径(NODE代码)
iconDirs: [path.resolve(process.cwd(), 'src/icons')]
//指定图标文件夹,绝对路径(NODE代码)
iconDirs: [path.resolve(process.cwd(), 'src/icons')],
symbolId: 'icon-[name]',
}),
// https://github.com/antfu/unocss
// Unocss(),

Loading…
Cancel
Save