Browse Source

feat: 患者列表

main
wally 2 years ago
parent
commit
937ac0920c
  1. 26
      App.vue
  2. 2
      api/base.ts
  3. 2
      api/index.ts
  4. 12
      api/modules/service.ts
  5. 18
      api/modules/user.ts
  6. 21
      components/SearchList/SearchList.vue
  7. 3
      components/SettingPad/SettingPad.vue
  8. 1
      config/local.ts
  9. 23
      config/service.ts
  10. 34
      hooks/usePagination.ts
  11. 6
      main.js
  12. 18
      manifest.json
  13. 3
      pages.json
  14. 72
      pages/patient-list/patient-list.vue
  15. 37
      store/modules/service.ts
  16. 8
      store/modules/user.ts
  17. 10
      uni.scss
  18. 9
      utils/common.ts
  19. 27
      utils/http.ts

26
App.vue

@ -1,12 +1,20 @@
<script>
import { useUserStoreWidthOut } from './store/modules/user'
import { useServiceStoreWidthOut } from './store/modules/service'
const userStore = useUserStoreWidthOut()
const serviceStore = useServiceStoreWidthOut()
export default {
onLaunch: function () {
async onLaunch() {
console.warn('当前组件仅支持 uni_modules 目录结构 ,请升级 HBuilderX 到 3.1.0 版本以上!')
console.log('App Launch')
this.login()
try {
await uni.$u.api.login()
this.getCarInfo()
} catch (error) {
uni.$u.alertError(error)
}
},
onShow: function () {
console.log('App Show')
@ -15,8 +23,18 @@ export default {
console.log('App Hide')
},
methods: {
login() {
userStore.login('P000001')
async getCarInfo() {
try {
const res = await uni.$u.api.getCarInfo()
serviceStore.setCurrentCar(res)
setTimeout(() => {
this.getCarInfo()
}, 1000)
} catch (error) {
console.error(error);
serviceStore.setCurrentCar(null)
throw error
}
}
}
}

2
api/base.ts

@ -9,7 +9,6 @@ export interface IParam {
export const post = (path: string, params: IParam) => {
let url = baseUrl + path
console.log('post: ', url)
// #ifdef APP-PLUS
if (!uni.host) {
@ -31,7 +30,6 @@ export const post = (path: string, params: IParam) => {
}
url = `${uni.host}${baseUrl}`
// #endif
console.log(params)
return uni.$u.post(url, params)
}

2
api/index.ts

@ -1,7 +1,9 @@
import { serviceApi } from './modules/service'
import { userApi } from './modules/user'
export function setupApi() {
uni.$u.api = {
...userApi,
...serviceApi,
}
}

12
api/modules/service.ts

@ -0,0 +1,12 @@
import { post } from '@/api/base'
// import { useUserStoreWidthOut } from '@/store/modules/user'
// const userStore = useUserStoreWidthOut()
export const serviceApi = {
// 查平车信息
getCarInfo: () => post('/car/queryByPadNo', { param: {} }),
// 查急救列表
getAidList: (keywords: string, pageNum = 1, pageSize = 20, sort = '') =>
post('/firstAid/list', { param: { keywords }, pageSize, pageNum, sort }),
}

18
api/modules/user.ts

@ -1,6 +1,22 @@
import { post } from '@/api/base'
import { useUserStoreWidthOut } from '@/store/modules/user'
const userStore = useUserStoreWidthOut()
export const userApi = {
// 登录
login: async (padNo: string) => post('/pad/login', { param: { padNo } }),
login: async () => {
const localDeviceNo = uni.getStorageSync(uni.$u.LOCAL_KEY.DEVICE_NO)
if (!localDeviceNo) {
uni.showModal({ title: '提示', content: '请先设置平板信息' })
return null
}
try {
const token = await post('/pad/login', { param: { padNo: localDeviceNo } })
userStore.setToken(token)
return token
} catch (error) {
throw new Error(error as any)
}
},
}

21
components/SearchList/SearchList.vue

@ -1,5 +1,5 @@
<template>
<view>
<view class="search-wrap">
<view class="bg-main-v border-radius-9-up u-p-r-40 flex ">
<image class="icon-car" src="@/static/images/car.png" mode="aspectFill" />
<text class="font-bold text-white">{{ carNo }}</text>
@ -12,14 +12,27 @@
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { computed, ref, onMounted } from 'vue';
import { useServiceStore } from '@/store/modules/service';
const carNo = ref('PC0001')
const emits = defineEmits(['on-search', 'on-load'])
const serviceStore = useServiceStore()
const searchValue = ref('')
function onSearch() {
const carNo = computed(() => serviceStore.carNo)
function onSearch() {
emits('on-search', searchValue.value)
}
onMounted(() => {
//// #ifdef H5
const el = document.querySelector('.search-wrap') as HTMLElement
emits('on-load', el.offsetHeight)
// #endif
})
</script>
<style lang="scss" scoped>

3
components/SettingPad/SettingPad.vue

@ -44,10 +44,11 @@ function onCancel() { emits('on-cancel') }
// confirm
function onConfirm() {
if (!formRef.value) return
formRef.value.validate().then(() => {
formRef.value.validate().then(async () => {
// localStorage
service.setDevice({ deviceNo: formData.SS_DEVICE_NO, host: formData.SS_ACCESS_HOST })
await uni.$u.api.login()
emits('on-confirm', formData)
}).catch(error => {
console.error(error);

1
config/local.ts

@ -2,4 +2,5 @@ export const LOCAL_KEY = {
LOADED: 'loaded', // 用来显示启动页 有本地数据不显示启动页 没有才显示
DEVICE_NO: 'SS_DEVICE_NO', // 平板编号
HOST: 'SS_ACCESS_HOST', // 域名
TOKEN: 'token',
}

23
config/service.ts

@ -0,0 +1,23 @@
// 性别列表
export const GENDER_LIST = [
{ text: '男', value: 0 },
{ text: '女', value: 1 },
]
/**
* value获取text
* @param {number} code gender value
* @return {string | undefined} /
*/
export function GET_GENDER_TEXT_BY_CODE(code: number): string | undefined {
const target = GENDER_LIST.find(item => item.value === code)
return target?.text
}
// 急救状态
export const AID_STATUS = {
0: '创建',
1: '待审核',
2: '审核通过',
3: '审核拒绝',
}

34
hooks/usePagination.ts

@ -0,0 +1,34 @@
import { reactive } from 'vue'
export function usePagination() {
const paginationRaw = {
pageNum: 1,
pageSize: 20,
hasNextPage: false,
nextPage: 0,
}
const pagination = reactive({ ...paginationRaw })
// update pagination
function updatePagination(res) {
if (!res) {
resetPagination()
return
}
const { nextPage, hasNextPage, pageNum, pageSize } = res
pagination.pageNum = pageNum || 1
pagination.nextPage = nextPage
pagination.hasNextPage = hasNextPage || false
pagination.pageSize = pageSize || 20
}
// reset pagination
function resetPagination() {
pagination.pageNum = 1
pagination.pageSize = 20
pagination.hasNextPage = false
pagination.nextPage = 0
}
return { pagination, updatePagination, resetPagination }
}

6
main.js

@ -1,16 +1,20 @@
import * as Pinia from 'pinia'
import * as service from '@/config/service'
import { alertError, openPage } from '@/utils/common'
import App from './App.vue'
import { LOCAL_KEY } from '@/config/local'
import { createSSRApp } from 'vue'
import { openPage } from '@/utils/common'
import { setupApi } from '@/api'
import { setupHttp } from '@/utils/http'
import { setupStore } from '@/store'
import uView from './uni_modules/vk-uview-ui'
uni.$u.openPage = openPage
uni.$u.alertError = alertError
uni.$u.LOCAL_KEY = LOCAL_KEY
uni.$u.service = { ...service }
export function createApp() {
const app = createSSRApp(App)

18
manifest.json

@ -81,11 +81,25 @@
"devServer": {
"open": false,
"proxy": {
"/service" : {
"/pad": {
"target": "http://test.tall.wiki:9002",
"changeOrigin": true,
"pathRewrite": {
"^/service" : ""
"^/pad": ""
}
},
"/car": {
"target": "http://test.tall.wiki:9002",
"changeOrigin": true,
"pathRewrite": {
"^/car": ""
}
},
"/firstAid": {
"target": "http://test.tall.wiki:9002",
"changeOrigin": true,
"pathRewrite": {
"^/firstAid": ""
}
}
}

3
pages.json

@ -10,13 +10,14 @@
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app",
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "pages/patient-list/patient-list",
"style": {
"navigationStyle": "custom",
"navigationBarTitleText": "患者列表"
}
},

72
pages/patient-list/patient-list.vue

@ -1,8 +1,10 @@
<template>
<view class="u-p-40 ">
<SearchList />
<view class="relative" :style="{ 'padding-top': `${searchHeight}px` }">
<SearchList ref="searchListRef" @on-search="onSearch" @on-load="onSearchLoad" />
<uni-section title="患者列表" type="line" class="uni-my-5" titleFontSize="16px"></uni-section>
<uni-grid :column="4" :highlight="true" :square="false" :show-border="false" @change="onClickItem">
<uni-grid-item :index="0" class="u-p-20 ">
<view class="list-item flex justify-center">
@ -12,16 +14,16 @@
</uni-grid-item>
<uni-grid-item v-for="(item, index) in data" :index="index + 1" :key="index + 1" class="u-p-20">
<view class="list-item flex active">
<view class="list-item flex " :class="{ active: currentAidId === item.firstAidId }">
<view class="flex-1">
<view class="text-title">
<text>{{ item.name }}</text>
<text>{{ item.age }}</text>
<text>{{ item.sex }}</text>
<text>{{ item.patientName }}</text>
<text>{{ item.patientAge }}</text>
<text>{{ GET_GENDER_TEXT_BY_CODE(item.patientGender) }}</text>
</view>
<view class="text-summary">
<u-tag :text="item.status" mode="light" size="mini" />
<text class="time">{{ item.time }}</text>
<u-tag :text="AID_STATUS[item.firstAidStatus]" mode="light" size="mini" />
<text class="time">{{ item.firstAidTime }}</text>
</view>
</view>
@ -34,32 +36,66 @@
<image class="create-user" src="@/static/images/bed.png" mode="scaleToFill" />
</view>
</view>
</template>
<script lang="ts" setup>
import type { IPatient } from '@/store/modules/service';
import { useServiceStore } from '@/store/modules/service';
import { usePagination } from '@/hooks/usePagination'
import { GET_GENDER_TEXT_BY_CODE, AID_STATUS } from '@/config/service'
import { computed, ref } from 'vue';
import { onReachBottom } from '@dcloudio/uni-app'
const serviceStore = useServiceStore()
const { pagination, updatePagination, resetPagination } = usePagination()
const data: IPatient[] = [
{ name: '脏兵', age: 17, sex: '男', status: '到院', time: '2022-11-23 12:11' },
{ name: '脏兵1', age: 17, sex: '男', status: '到院', time: '2022-11-23 12:11' },
{ name: '脏兵2', age: 17, sex: '男', status: '到院', time: '2022-11-23 12:11' },
{ name: '脏兵3', age: 17, sex: '男', status: '到院', time: '2022-11-23 12:11' },
{ name: '脏兵4', age: 17, sex: '男', status: '到院', time: '2022-11-23 12:11' },
{ name: '脏兵', age: 17, sex: '男', status: '到院', time: '2022-11-23 12:11' },
{ name: '脏兵1', age: 17, sex: '男', status: '到院', time: '2022-11-23 12:11' },
{ name: '脏兵2', age: 17, sex: '男', status: '到院', time: '2022-11-23 12:11' },
{ name: '脏兵3', age: 17, sex: '男', status: '到院', time: '2022-11-23 12:11' },
]
const data = ref<IPatient[]>([])
const keywords = ref('')
const searchHeight = ref(100)
const currentAidId = computed(() => serviceStore.currentPatient?.firstAidId)
function onClickItem(event) {
const item = data[event.detail.index]
serviceStore.setCurrentPatient(item)
uni.$u.openPage('detail2')
}
function onSearch(searchValue: string) {
keywords.value = searchValue
resetPagination()
getAidList()
}
// get list
async function getAidList() {
try {
const res = await uni.$u.api.getAidList(keywords.value, pagination.nextPage || 1, pagination.pageSize)
data.value = res?.list || []
updatePagination(res) //
} catch (error) {
console.error(error);
}
}
function onSearchLoad(height: number) {
searchHeight.value = height
}
onSearch('')
onReachBottom(() => {
console.log('reach bottom', pagination);
if (pagination.nextPage === 0) {
uni.$u.toast('没有更多数据')
return
}
getAidList()
})
</script>
<style lang="scss" scoped>

37
store/modules/service.ts

@ -2,17 +2,34 @@ import { defineStore } from 'pinia'
import { store } from '@/store'
export interface IPatient {
name: string
gender?: number
idCard?: string
status?: string
age?: number
sex?: string
time?: string
demoFlag: number
firstAidId: string
firstAidStatus: string
firstAidTime: string
firstAidZlType: number
patientAge: null | number
patientGender: number
patientIdCardNo: string
patientName: string
patientNation: string
sourceId: string
sourceType: number
}
// 平车信息
export interface ICar {
carNo: string
online: number // 0 离线 1在线
powerLowAlarm: number // 0 正常 1 报警
sensorAngleV: null | number // 角度
sensorPower: null | string // 电量百分比
sensorVibrate: null | string // 振幅
sensorWeight: null | string // 重量
}
export interface ServiceState {
currentPatient: null | IPatient
currentCar: null | ICar
device: null | { deviceNo: string; host: string }
}
@ -21,11 +38,13 @@ export const useServiceStore = defineStore({
state: (): ServiceState => ({
currentPatient: null, // 当前病友的信息
device: null, // 当前设备的信息
currentCar: null, // 车的信息
}),
getters: {
deviceNo: ({ device }) => device?.deviceNo || '',
host: ({ device }) => device?.host || '',
carNo: ({ currentCar }) => currentCar?.carNo || '', // 平车编号
},
actions: {
@ -33,6 +52,10 @@ export const useServiceStore = defineStore({
this.currentPatient = patient
},
setCurrentCar(car: ICar | null) {
this.currentCar = car || null
},
// 设置设备信息
setDevice(device: null | { deviceNo: string; host: string }) {
this.device = device

8
store/modules/user.ts

@ -4,12 +4,14 @@ import { store } from '@/store'
interface UserState {
user: null | IUser // 用户信息
token: string
}
export const useUserStore = defineStore({
id: 'user',
state: (): UserState => ({
user: null,
token: '',
}),
getters: {},
@ -45,6 +47,12 @@ export const useUserStore = defineStore({
}
},
// set token
setToken(token: string) {
this.token = token
uni.setStorageSync(uni.$u.LOCAL_KEY.TOKEN, token)
},
setUser(data) {
this.user = data || null
},

10
uni.scss

@ -141,3 +141,13 @@ $u-type-success: #1bb299;
.uni-section .uni-section-header__content .distraction {
font-weight: bold;
}
.search-wrap {
z-index: 9999;
position: fixed;
left: 0;
top: 0;
right: 0;
padding: 20px;
background-color: #fff;
}

9
utils/common.ts

@ -16,3 +16,12 @@ export function openPage(pageName: string, isRedirect = false, query?: string) {
}, 1000)
}
}
// show modal 显示弹窗
export function alertError(error: any) {
let msg = error
if (typeof error === 'object') {
msg = JSON.stringify(error)
}
uni.showModal({ title: '提示', content: msg, showCancel: false })
}

27
utils/http.ts

@ -1,8 +1,11 @@
const WHITE_LIST = ['/pad/login']
import { useUserStoreWidthOut } from '@/store/modules/user'
const userStore = useUserStoreWidthOut()
export function setupHttp() {
uni.$u.http.setConfig({
// #ifdef H5
baseUrl: '/service',
// #endif
loadingText: '努力加载中~',
loadingTime: 800,
header: {
@ -15,6 +18,11 @@ export function setupHttp() {
uni.$u.http.interceptor.request = config => {
// 可以对某个url进行特别处理,此url参数为this.$u.get(url)中的url值
// 最后需要将config进行return
if (!WHITE_LIST.includes(config.url)) {
// 不在 白名单里的请求 加token
config.header.Authorization = `Bearer ${userStore.token}`
}
uni.$u.count = 0
return config
// 如果return一个false值,则会取消本次请求
@ -24,13 +32,20 @@ export function setupHttp() {
// 响应拦截,判断状态码是否通过
uni.$u.http.interceptor.response = res => {
if (!res) return Promise.reject('res is null')
console.log('res: ', res)
const { code, msg, data } = res
// console.log(code, msg, data, )
if (code === 200) {
return Promise.resolve(data)
} else if (code === 401) {
uni.$u.api
.login()
.then(() => {
// TODO: 登录成功后重发请求
})
.catch((error: any) => {
uni.$u.alertError(error)
return Promise.reject('登录过期, 且自动登录失败')
})
} else {
uni.$u.toast(msg || '请求发生错误')
return Promise.reject(msg)

Loading…
Cancel
Save