Compare commits
12 Commits
b443454bab
...
intc-healt
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6ecdec407 | ||
|
|
65239f57ba | ||
|
|
3294695dec | ||
|
|
68da3c0101 | ||
|
|
88cf663855 | ||
|
|
cc1ccad308 | ||
|
|
aeb1e39920 | ||
|
|
6aaf564800 | ||
|
|
6846ea3e0f | ||
|
|
9027869e97 | ||
|
|
be3135b166 | ||
|
|
2297b19c2b |
3
package-lock.json
generated
3
package-lock.json
generated
@@ -7,6 +7,7 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "uni-preset-vue",
|
"name": "uni-preset-vue",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dcloudio/uni-app": "3.0.0-4000820240401001",
|
"@dcloudio/uni-app": "3.0.0-4000820240401001",
|
||||||
"@dcloudio/uni-app-plus": "3.0.0-4000820240401001",
|
"@dcloudio/uni-app-plus": "3.0.0-4000820240401001",
|
||||||
@@ -12490,7 +12491,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/uview-plus": {
|
"node_modules/uview-plus": {
|
||||||
"version": "3.1.45",
|
"version": "3.1.45",
|
||||||
"resolved": "https://registry.npmmirror.com/uview-plus/-/uview-plus-3.1.45.tgz",
|
"resolved": "https://registry.npmjs.org/uview-plus/-/uview-plus-3.1.45.tgz",
|
||||||
"integrity": "sha512-JHgLp2heaMciLdGimO/v4tMM8iwb2vTEOk6sXqn5X198AHjM5A/IGzH84GZPvUISFTEJbxGEHiGPxpv2K26AGw==",
|
"integrity": "sha512-JHgLp2heaMciLdGimO/v4tMM8iwb2vTEOk6sXqn5X198AHjM5A/IGzH84GZPvUISFTEJbxGEHiGPxpv2K26AGw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -38,7 +38,15 @@
|
|||||||
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
|
"build:quickapp-webview-union": "uni build -p quickapp-webview-union",
|
||||||
"type-check": "vue-tsc --noEmit",
|
"type-check": "vue-tsc --noEmit",
|
||||||
"clean:linux": "rm -rf dist || rm -rf node_modules",
|
"clean:linux": "rm -rf dist || rm -rf node_modules",
|
||||||
"clean:windows": "rd /s /q dist || rd /s /q node_modules"
|
"clean:windows": "rd /s /q dist || rd /s /q node_modules",
|
||||||
|
"patch:u-input": "node scripts/patch-u-input.js",
|
||||||
|
"postinstall": "node scripts/patch-u-input.js",
|
||||||
|
"predev:mp-weixin": "node scripts/patch-u-input.js",
|
||||||
|
"prebuild:mp-weixin": "node scripts/patch-u-input.js",
|
||||||
|
"predev:h5": "node scripts/patch-u-input.js",
|
||||||
|
"prebuild:h5": "node scripts/patch-u-input.js",
|
||||||
|
"predev:app": "node scripts/patch-u-input.js",
|
||||||
|
"prebuild:app": "node scripts/patch-u-input.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@dcloudio/uni-app": "3.0.0-4000820240401001",
|
"@dcloudio/uni-app": "3.0.0-4000820240401001",
|
||||||
|
|||||||
23
scripts/patch-u-input.js
Normal file
23
scripts/patch-u-input.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* uView u-input 组件补丁
|
||||||
|
* 直接用预存的补丁文件覆盖原始文件
|
||||||
|
* 使下拉选择框(readonly/disabled)超长文字可自动换行完整显示
|
||||||
|
*/
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const target = path.join('node_modules', 'uview-plus', 'components', 'u-input', 'u-input.vue');
|
||||||
|
const source = path.join('scripts', 'u-input.vue');
|
||||||
|
|
||||||
|
if (!fs.existsSync(target)) {
|
||||||
|
console.log('[patch-u-input] target not found, skipping');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(source)) {
|
||||||
|
console.log('[patch-u-input] source not found, skipping');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.copyFileSync(source, target);
|
||||||
|
console.log('[patch-u-input] Patched successfully');
|
||||||
494
scripts/u-input.vue
Normal file
494
scripts/u-input.vue
Normal file
@@ -0,0 +1,494 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-input"
|
||||||
|
:class="[inputClass, isSelectLike ? 'u-input--selectlike' : '', isSearchInput ? 'u-input--search-input' : '']"
|
||||||
|
:style="[wrapperStyle]"
|
||||||
|
>
|
||||||
|
<view class="u-input__content">
|
||||||
|
<view
|
||||||
|
class="u-input__content__prefix-icon"
|
||||||
|
v-if="prefixIcon || $slots.prefix"
|
||||||
|
>
|
||||||
|
<slot name="prefix">
|
||||||
|
<u-icon
|
||||||
|
:name="prefixIcon"
|
||||||
|
size="18"
|
||||||
|
:customStyle="prefixIconStyle"
|
||||||
|
></u-icon>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
<view class="u-input__content__field-wrapper" @tap="clickHandler">
|
||||||
|
<!-- 根据uni-app的input组件文档,H5和APP中只要声明了password参数(无论true还是false),type均失效,此时
|
||||||
|
为了防止type=number时,又存在password属性,type无效,此时需要设置password为undefined
|
||||||
|
-->
|
||||||
|
<!-- 选择型(readonly/disabled)用 view 显示文字,支持自动换行 -->
|
||||||
|
<view
|
||||||
|
v-if="isSelectLike"
|
||||||
|
class="u-input__content__field-wrapper__field u-input__content__field-wrapper__field--selectlike"
|
||||||
|
:style="[inputStyle]"
|
||||||
|
>
|
||||||
|
<text v-if="innerValue" class="u-input__content__field-wrapper__field__text">{{ innerValue }}</text>
|
||||||
|
<text v-else class="u-input__content__field-wrapper__field__placeholder">{{ placeholder }}</text>
|
||||||
|
</view>
|
||||||
|
<!-- 普通输入模式保持原生 input -->
|
||||||
|
<input
|
||||||
|
v-else
|
||||||
|
class="u-input__content__field-wrapper__field"
|
||||||
|
:style="[inputStyle]"
|
||||||
|
:type="type"
|
||||||
|
:focus="focus"
|
||||||
|
:cursor="cursor"
|
||||||
|
:value="innerValue"
|
||||||
|
:auto-blur="autoBlur"
|
||||||
|
:disabled="disabled || readonly"
|
||||||
|
:maxlength="maxlength"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:placeholder-style="placeholderStyle"
|
||||||
|
:placeholder-class="placeholderClass"
|
||||||
|
:confirm-type="confirmType"
|
||||||
|
:confirm-hold="confirmHold"
|
||||||
|
:hold-keyboard="holdKeyboard"
|
||||||
|
:cursor-spacing="cursorSpacing"
|
||||||
|
:adjust-position="adjustPosition"
|
||||||
|
:selection-end="selectionEnd"
|
||||||
|
:selection-start="selectionStart"
|
||||||
|
:password="password || type === 'password' || undefined"
|
||||||
|
:ignoreCompositionEvent="ignoreCompositionEvent"
|
||||||
|
@input="onInput"
|
||||||
|
@blur="onBlur"
|
||||||
|
@focus="onFocus"
|
||||||
|
@confirm="onConfirm"
|
||||||
|
@keyboardheightchange="onkeyboardheightchange"
|
||||||
|
@change="onInput"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-input__content__clear"
|
||||||
|
v-if="isShowClear"
|
||||||
|
@click="onClear"
|
||||||
|
>
|
||||||
|
<u-icon
|
||||||
|
name="close"
|
||||||
|
size="11"
|
||||||
|
color="#ffffff"
|
||||||
|
customStyle="line-height: 12px"
|
||||||
|
></u-icon>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-input__content__subfix-icon"
|
||||||
|
v-if="suffixIcon || $slots.suffix"
|
||||||
|
>
|
||||||
|
<slot name="suffix">
|
||||||
|
<u-icon
|
||||||
|
:name="suffixIcon"
|
||||||
|
size="18"
|
||||||
|
:customStyle="suffixIconStyle"
|
||||||
|
></u-icon>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from "./props.js";
|
||||||
|
import mpMixin from '../../libs/mixin/mpMixin.js';
|
||||||
|
import mixin from '../../libs/mixin/mixin.js';
|
||||||
|
/**
|
||||||
|
* Input 输入框
|
||||||
|
* @description 此组件为一个输入框,默认没有边框和样式,是专门为配合表单组件u-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。
|
||||||
|
* @tutorial https://uiadmin.net/uview-plus/components/input.html
|
||||||
|
* @property {String | Number} value 输入的值
|
||||||
|
* @property {String} type 输入框类型,见上方说明 ( 默认 'text' )
|
||||||
|
* @property {Boolean} fixed 如果 textarea 是在一个 position:fixed 的区域,需要显示指定属性 fixed 为 true,兼容性:微信小程序、百度小程序、字节跳动小程序、QQ小程序 ( 默认 false )
|
||||||
|
* @property {Boolean} disabled 是否禁用输入框 ( 默认 false )
|
||||||
|
* @property {String} disabledColor 禁用状态时的背景色( 默认 '#f5f7fa' )
|
||||||
|
* @property {Boolean} clearable 是否显示清除控件 ( 默认 false )
|
||||||
|
* @property {Boolean} password 是否密码类型 ( 默认 false )
|
||||||
|
* @property {String | Number} maxlength 最大输入长度,设置为 -1 的时候不限制最大长度 ( 默认 -1 )
|
||||||
|
* @property {String} placeholder 输入框为空时的占位符
|
||||||
|
* @property {String} placeholderClass 指定placeholder的样式类,注意页面或组件的style中写了scoped时,需要在类名前写/deep/ ( 默认 'input-placeholder' )
|
||||||
|
* @property {String | Object} placeholderStyle 指定placeholder的样式,字符串/对象形式,如"color: red;"
|
||||||
|
* @property {Boolean} showWordLimit 是否显示输入字数统计,只在 type ="text"或type ="textarea"时有效 ( 默认 false )
|
||||||
|
* @property {String} confirmType 设置右下角按钮的文字,兼容性详见uni-app文档 ( 默认 'done' )
|
||||||
|
* @property {Boolean} confirmHold 点击键盘右下角按钮时是否保持键盘不收起,H5无效 ( 默认 false )
|
||||||
|
* @property {Boolean} holdKeyboard focus时,点击页面的时候不收起键盘,微信小程序有效 ( 默认 false )
|
||||||
|
* @property {Boolean} focus 自动获取焦点,在 H5 平台能否聚焦以及软键盘是否跟随弹出,取决于当前浏览器本身的实现。nvue 页面不支持,需使用组件的 focus()、blur() 方法控制焦点 ( 默认 false )
|
||||||
|
* @property {Boolean} autoBlur 键盘收起时,是否自动失去焦点,目前仅App3.0.0+有效 ( 默认 false )
|
||||||
|
* @property {Boolean} disableDefaultPadding 是否去掉 iOS 下的默认内边距,仅微信小程序,且type=textarea时有效 ( 默认 false )
|
||||||
|
* @property {String | Number} cursor 指定focus时光标的位置( 默认 -1 )
|
||||||
|
* @property {String | Number} cursorSpacing 输入框聚焦时底部与键盘的距离 ( 默认 30 )
|
||||||
|
* @property {String | Number} selectionStart 光标起始位置,自动聚集时有效,需与selection-end搭配使用 ( 默认 -1 )
|
||||||
|
* @property {String | Number} selectionEnd 光标结束位置,自动聚集时有效,需与selection-start搭配使用 ( 默认 -1 )
|
||||||
|
* @property {Boolean} adjustPosition 键盘弹起时,是否自动上推页面 ( 默认 true )
|
||||||
|
* @property {String} inputAlign 输入框内容对齐方式( 默认 'left' )
|
||||||
|
* @property {String | Number} fontSize 输入框字体的大小 ( 默认 '15px' )
|
||||||
|
* @property {String} color 输入框字体颜色 ( 默认 '#303133' )
|
||||||
|
* @property {Function} formatter 内容式化函数
|
||||||
|
* @property {String} prefixIcon 输入框前置图标
|
||||||
|
* @property {String | Object} prefixIconStyle 前置图标样式,对象或字符串
|
||||||
|
* @property {String} suffixIcon 输入框后置图标
|
||||||
|
* @property {String | Object} suffixIconStyle 后置图标样式,对象或字符串
|
||||||
|
* @property {String} border 边框类型,surround-四周边框,bottom-底部边框,none-无边框 ( 默认 'surround' )
|
||||||
|
* @property {Boolean} readonly 是否只读,与disabled不同之处在于disabled会置灰组件,而readonly则不会 ( 默认 false )
|
||||||
|
* @property {String} shape 输入框形状,circle-圆形,square-方形 ( 默认 'square' )
|
||||||
|
* @property {Object} customStyle 定义需要用到的外部样式
|
||||||
|
* @property {Boolean} ignoreCompositionEvent 是否忽略组件内对文本合成系统事件的处理。
|
||||||
|
* @example <u-input v-model="value" :password="true" suffix-icon="lock-fill" />
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-input",
|
||||||
|
mixins: [mpMixin, mixin, props],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 输入框的值
|
||||||
|
innerValue: "",
|
||||||
|
// 是否处于获得焦点状态
|
||||||
|
focused: false,
|
||||||
|
// value是否第一次变化,在watch中,由于加入immediate属性,会在第一次触发,此时不应该认为value发生了变化
|
||||||
|
firstChange: true,
|
||||||
|
// value绑定值的变化是由内部还是外部引起的
|
||||||
|
changeFromInner: false,
|
||||||
|
// 过滤处理方法
|
||||||
|
innerFormatter: value => value
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// #ifdef VUE3
|
||||||
|
modelValue: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal, oldVal) {
|
||||||
|
this.innerValue = newVal;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
// 在H5中,外部value变化后,修改input中的值,不会触发@input事件,此时手动调用值变化方法
|
||||||
|
if (
|
||||||
|
this.firstChange === false &&
|
||||||
|
this.changeFromInner === false
|
||||||
|
) {
|
||||||
|
this.valueChange();
|
||||||
|
} else {
|
||||||
|
// 尝试调用u-form的验证方法
|
||||||
|
uni.$u.formValidate(this, "change");
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
this.firstChange = false;
|
||||||
|
// 重置changeFromInner的值为false,标识下一次引起默认为外部引起的
|
||||||
|
this.changeFromInner = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
// #ifdef VUE2
|
||||||
|
value: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal, oldVal) {
|
||||||
|
this.innerValue = newVal;
|
||||||
|
/* #ifdef H5 */
|
||||||
|
// 在H5中,外部value变化后,修改input中的值,不会触发@input事件,此时手动调用值变化方法
|
||||||
|
if (
|
||||||
|
this.firstChange === false &&
|
||||||
|
this.changeFromInner === false
|
||||||
|
) {
|
||||||
|
this.valueChange();
|
||||||
|
} else {
|
||||||
|
// 尝试调用u-form的验证方法
|
||||||
|
uni.$u.formValidate(this, "change");
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
this.firstChange = false;
|
||||||
|
// 重置changeFromInner的值为false,标识下一次引起默认为外部引起的
|
||||||
|
this.changeFromInner = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isSelectLike() {
|
||||||
|
return this.type === 'select' || this.disabled || this.readonly
|
||||||
|
},
|
||||||
|
isSearchInput() {
|
||||||
|
const customStyle = this.customStyle
|
||||||
|
if (typeof customStyle === 'string') {
|
||||||
|
return customStyle.includes('height: 66rpx') && customStyle.includes('border-radius: 24rpx')
|
||||||
|
}
|
||||||
|
const style = uni.$u.addStyle(customStyle)
|
||||||
|
return style.height === '66rpx' && (style.borderRadius === '24rpx' || style['border-radius'] === '24rpx')
|
||||||
|
},
|
||||||
|
// 是否显示清除控件
|
||||||
|
isShowClear() {
|
||||||
|
const { clearable, readonly, focused, innerValue } = this;
|
||||||
|
return !!clearable && !readonly && !!focused && innerValue !== "";
|
||||||
|
},
|
||||||
|
// 组件的类名
|
||||||
|
inputClass() {
|
||||||
|
let classes = [],
|
||||||
|
{ border, disabled, shape } = this;
|
||||||
|
border === "surround" &&
|
||||||
|
(classes = classes.concat(["u-border", "u-input--radius"]));
|
||||||
|
classes.push(`u-input--${shape}`);
|
||||||
|
border === "bottom" &&
|
||||||
|
(classes = classes.concat([
|
||||||
|
"u-border-bottom",
|
||||||
|
"u-input--no-radius",
|
||||||
|
]));
|
||||||
|
return classes.join(" ");
|
||||||
|
},
|
||||||
|
// 组件的样式
|
||||||
|
wrapperStyle() {
|
||||||
|
const style = {};
|
||||||
|
// 禁用状态下,被背景色加上对应的样式
|
||||||
|
if (this.disabled) {
|
||||||
|
style.backgroundColor = this.disabledColor;
|
||||||
|
}
|
||||||
|
// 无边框时,去除内边距
|
||||||
|
if (this.border === "none") {
|
||||||
|
style.padding = "0";
|
||||||
|
} else {
|
||||||
|
// 由于uni-app的iOS开发者能力有限,导致需要分开写才有效
|
||||||
|
style.paddingTop = "6px";
|
||||||
|
style.paddingBottom = "6px";
|
||||||
|
style.paddingLeft = "9px";
|
||||||
|
style.paddingRight = "9px";
|
||||||
|
}
|
||||||
|
const mergedStyle = uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle));
|
||||||
|
if (this.isSearchInput) {
|
||||||
|
mergedStyle.height = '66rpx';
|
||||||
|
mergedStyle.minHeight = '66rpx';
|
||||||
|
mergedStyle.boxSizing = 'border-box';
|
||||||
|
mergedStyle.paddingTop = '0';
|
||||||
|
mergedStyle.paddingBottom = '0';
|
||||||
|
}
|
||||||
|
return mergedStyle;
|
||||||
|
},
|
||||||
|
// 输入框的样式
|
||||||
|
inputStyle() {
|
||||||
|
const style = {
|
||||||
|
color: this.color,
|
||||||
|
fontSize: uni.$u.addUnit(this.fontSize),
|
||||||
|
textAlign: this.inputAlign
|
||||||
|
};
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// #ifdef VUE3
|
||||||
|
emits: ['update:modelValue', 'focus', 'blur', 'change', 'confirm', 'clear', 'keyboardheightchange', 'click'],
|
||||||
|
// #endif
|
||||||
|
methods: {
|
||||||
|
// 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用
|
||||||
|
setFormatter(e) {
|
||||||
|
this.innerFormatter = e
|
||||||
|
},
|
||||||
|
// 当键盘输入时,触发input事件
|
||||||
|
onInput(e) {
|
||||||
|
let { value = "" } = e.detail || {};
|
||||||
|
// 格式化过滤方法
|
||||||
|
const formatter = this.formatter || this.innerFormatter
|
||||||
|
const formatValue = formatter(value)
|
||||||
|
// 为了避免props的单向数据流特性,需要先将innerValue值设置为当前值,再在$nextTick中重新赋予设置后的值才有效
|
||||||
|
this.innerValue = value
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.innerValue = formatValue;
|
||||||
|
this.valueChange();
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 输入框失去焦点时触发
|
||||||
|
onBlur(event) {
|
||||||
|
this.$emit("blur", event.detail.value);
|
||||||
|
// H5端的blur会先于点击清除控件的点击click事件触发,导致focused
|
||||||
|
// 瞬间为false,从而隐藏了清除控件而无法被点击到
|
||||||
|
uni.$u.sleep(150).then(() => {
|
||||||
|
this.focused = false;
|
||||||
|
});
|
||||||
|
// 尝试调用u-form的验证方法
|
||||||
|
uni.$u.formValidate(this, "blur");
|
||||||
|
},
|
||||||
|
// 输入框聚焦时触发
|
||||||
|
onFocus(event) {
|
||||||
|
this.focused = true;
|
||||||
|
this.$emit("focus");
|
||||||
|
},
|
||||||
|
// 点击完成按钮时触发
|
||||||
|
onConfirm(event) {
|
||||||
|
this.$emit("confirm", this.innerValue);
|
||||||
|
},
|
||||||
|
// 键盘高度发生变化的时候触发此事件
|
||||||
|
// 兼容性:微信小程序2.7.0+、App 3.1.0+
|
||||||
|
onkeyboardheightchange(event) {
|
||||||
|
this.$emit("keyboardheightchange", event);
|
||||||
|
},
|
||||||
|
// 内容发生变化,进行处理
|
||||||
|
valueChange() {
|
||||||
|
const value = this.innerValue;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// #ifdef VUE3
|
||||||
|
this.$emit("update:modelValue", value);
|
||||||
|
// #endif
|
||||||
|
// #ifdef VUE2
|
||||||
|
this.$emit("input", value);
|
||||||
|
// #endif
|
||||||
|
// 标识value值的变化是由内部引起的
|
||||||
|
this.changeFromInner = true;
|
||||||
|
this.$emit("change", value);
|
||||||
|
// 尝试调用u-form的验证方法
|
||||||
|
uni.$u.formValidate(this, "change");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 点击清除控件
|
||||||
|
onClear() {
|
||||||
|
this.innerValue = "";
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.valueChange();
|
||||||
|
this.$emit("clear");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 在安卓nvue上,事件无法冒泡
|
||||||
|
* 在某些时间,我们希望监听u-from-item的点击事件,此时会导致点击u-form-item内的u-input后
|
||||||
|
* 无法触发u-form-item的点击事件,这里通过手动调用u-form-item的方法进行触发
|
||||||
|
*/
|
||||||
|
clickHandler() {
|
||||||
|
this.$emit('click')
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
if (uni.$u.os() === "android") {
|
||||||
|
const formItem = uni.$u.$parent.call(this, "u-form-item");
|
||||||
|
if (formItem) {
|
||||||
|
formItem.clickHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
.u-input {
|
||||||
|
@include flex(row);
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&--selectlike {
|
||||||
|
/* 覆盖 inline style 的固定 height,让普通选择型内容可自适应换行 */
|
||||||
|
/* 短文字垂直居中,长文字撑开高度自动换行 */
|
||||||
|
height: auto !important;
|
||||||
|
min-height: 68rpx;
|
||||||
|
|
||||||
|
/* 只让展示文本本身不抢事件,保留外层点击与 suffix 插槽事件 */
|
||||||
|
.u-input__content__field-wrapper__field {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--search-input {
|
||||||
|
/* 列表页顶部查询框必须同高;该 class 在组件内部计算,兼容小程序组件样式隔离 */
|
||||||
|
height: 66rpx !important;
|
||||||
|
min-height: 66rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-top: 0 !important;
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
|
||||||
|
.u-input__content,
|
||||||
|
.u-input__content__field-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-input__content__field-wrapper__field--selectlike {
|
||||||
|
min-height: 0;
|
||||||
|
line-height: 32rpx;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-break: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-input__content__field-wrapper__field__text,
|
||||||
|
.u-input__content__field-wrapper__field__placeholder {
|
||||||
|
line-height: 32rpx;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--radius,
|
||||||
|
&--square {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--no-radius {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--circle {
|
||||||
|
border-radius: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
flex: 1;
|
||||||
|
@include flex(row);
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&__field-wrapper {
|
||||||
|
position: relative;
|
||||||
|
@include flex(row);
|
||||||
|
margin: 0;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&__field {
|
||||||
|
line-height: 26px;
|
||||||
|
text-align: left;
|
||||||
|
color: $u-main-color;
|
||||||
|
height: 24px;
|
||||||
|
font-size: 15px;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
/* 选择型模式:用 view 代替 input,支持自动换行 */
|
||||||
|
&--selectlike {
|
||||||
|
min-height: 24px;
|
||||||
|
height: auto !important;
|
||||||
|
line-height: 26px;
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: normal;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
color: $u-main-color;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__placeholder {
|
||||||
|
color: $u-light-color;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 26px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__clear {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 100px;
|
||||||
|
background-color: #c6c7cb;
|
||||||
|
@include flex(row);
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transform: scale(0.82);
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subfix-icon {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__prefix-icon {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -19,9 +19,12 @@ export function login(username, password, code, uuid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户详细信息
|
// 获取用户详细信息
|
||||||
export function getInfo() {
|
export function getInfo(silentAuth = false) {
|
||||||
return request({
|
return request({
|
||||||
'url': '/system/user/getInfo',
|
'url': '/system/user/getInfo',
|
||||||
|
headers: silentAuth ? {
|
||||||
|
silentAuth: true
|
||||||
|
} : undefined,
|
||||||
'method': 'get'
|
'method': 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
21
src/api/system/feedback.js
Normal file
21
src/api/system/feedback.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
import upload from '@/utils/upload'
|
||||||
|
|
||||||
|
// 提交意见反馈(H5/小程序端)
|
||||||
|
export function submitFeedback(data) {
|
||||||
|
return request({
|
||||||
|
url: '/system/feedback/submit',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传反馈截图
|
||||||
|
export function uploadFeedbackImage(filePath) {
|
||||||
|
return upload({
|
||||||
|
url: '/file/upload',
|
||||||
|
filePath,
|
||||||
|
name: 'file',
|
||||||
|
formData: {}
|
||||||
|
})
|
||||||
|
}
|
||||||
35
src/mixins/share.js
Normal file
35
src/mixins/share.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import config from '@/config.js'
|
||||||
|
|
||||||
|
const SHARE_HOME = '/pages/login'
|
||||||
|
const SHARE_TITLES = {
|
||||||
|
'intc-invest-app': '智聪记账管理平台',
|
||||||
|
'intc-health-app': '暖康档案管理平台'
|
||||||
|
}
|
||||||
|
|
||||||
|
function getShareTitle() {
|
||||||
|
return SHARE_TITLES[config.appInfo?.name] || config.appInfo?.name || '智聪管理平台'
|
||||||
|
}
|
||||||
|
|
||||||
|
function showShareMenu() {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
uni.showShareMenu({
|
||||||
|
withShareTicket: true,
|
||||||
|
menus: ['shareAppMessage']
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
onLoad() {
|
||||||
|
showShareMenu()
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
showShareMenu()
|
||||||
|
},
|
||||||
|
onShareAppMessage() {
|
||||||
|
return {
|
||||||
|
title: getShareTitle(),
|
||||||
|
path: SHARE_HOME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
472
src/pages.json
472
src/pages.json
@@ -62,12 +62,6 @@
|
|||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"path": "pages/health/statistic/index",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "pages/mine",
|
"path": "pages/mine",
|
||||||
"style": {
|
"style": {
|
||||||
@@ -75,160 +69,6 @@
|
|||||||
"navigationStyle": "custom"
|
"navigationStyle": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"path": "pages/health/doctorRecord/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "就医记录"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/doctorRecord/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "就医记录"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/doctorRecord/costList",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "费用明细"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/doctorRecord/costAddEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "费用明细"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/healthRecord/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "健康档案"
|
|
||||||
}
|
|
||||||
} ,
|
|
||||||
{
|
|
||||||
"path": "pages/health/healthRecord/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "健康档案"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/healthRecord/details",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "档案统计"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/marRecord/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "用药记录"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/marRecord/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "用药记录"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/medicineBasic/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "药品基础信息"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/medicineBasic/details",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "药品基础信息详情"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/medicineBasic/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "药品基础信息"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/medicineStockIn/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "药品入库清单"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/medicineStockIn/details",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "药品入库清单详情"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/medicineStockIn/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "药品入库清单"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"path": "pages/health/medicineStock/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "药品实时库存"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/temperatureRecord/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "体温记录"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/temperatureRecord/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "体温记录"
|
|
||||||
}
|
|
||||||
} ,
|
|
||||||
{
|
|
||||||
"path": "pages/health/processRecord/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "档案过程记录"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/processRecord/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "过程记录"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/heightWeightRecord/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "身高体重记录"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/milkPowderRecord/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "吃奶记录"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/milkPowderRecord/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "吃奶记录"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
{
|
|
||||||
"path": "pages/health/heightWeightRecord/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "身高体重记录"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "pages/health/person/list",
|
"path": "pages/health/person/list",
|
||||||
"style": {
|
"style": {
|
||||||
@@ -256,83 +96,44 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/health/statistic/doctorStatistic/index",
|
"path": "pages/health/temperatureRecord/list",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "就医统计"
|
"navigationBarTitleText": "体温记录"
|
||||||
}
|
}
|
||||||
} ,
|
}
|
||||||
|
,
|
||||||
{
|
{
|
||||||
"path": "pages/health/statistic/healthStatistic/index",
|
"path": "pages/health/temperatureRecord/addEdit",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "档案统计"
|
"navigationBarTitleText": "体温记录"
|
||||||
|
}
|
||||||
|
} ,
|
||||||
|
{
|
||||||
|
"path": "pages/health/heightWeightRecord/list",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "身高体重记录"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
"path": "pages/health/milkPowderRecord/addEdit",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "吃奶记录"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/health/statistic/healthScreen/index",
|
"path": "pages/health/milkPowderRecord/list",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "健康总览态势"
|
"navigationBarTitleText": "吃奶记录"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
{
|
,
|
||||||
"path": "pages/health/statistic/recordScreen/index",
|
{
|
||||||
"style": {
|
"path": "pages/health/heightWeightRecord/addEdit",
|
||||||
"navigationBarTitleText": "健康档案态势"
|
"style": {
|
||||||
}
|
"navigationBarTitleText": "身高体重记录"
|
||||||
} ,
|
}
|
||||||
{
|
},
|
||||||
"path": "pages/health/statistic/marStatistic/index",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "用药统计"
|
|
||||||
}
|
|
||||||
} ,
|
|
||||||
{
|
|
||||||
"path": "pages/health/statistic/temperatureStatistic/index",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "体温统计"
|
|
||||||
}
|
|
||||||
} ,
|
|
||||||
{
|
|
||||||
"path": "pages/health/statistic/milkPowderStatistic/index",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "吃奶量统计"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/medicationPlan/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "用药计划"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/medicationPlan/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "用药计划"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/chronicDisease/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "慢性疾病档案"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/chronicDisease/addEdit",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "慢性疾病档案"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/chronicDisease/details",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "慢性疾病详情"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/health/medicationTask/list",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "服药任务"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "pages/health/healthTags/list",
|
"path": "pages/health/healthTags/list",
|
||||||
"style": {
|
"style": {
|
||||||
@@ -386,6 +187,12 @@
|
|||||||
"navigationBarTitleText": "常见问题"
|
"navigationBarTitleText": "常见问题"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "feedback/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "意见反馈"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "about/index",
|
"path": "about/index",
|
||||||
"style": {
|
"style": {
|
||||||
@@ -393,9 +200,212 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/statistic",
|
||||||
|
"name": "statistic",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "index",
|
||||||
|
"style": { "navigationBarTitleText": "统计分析" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "doctorStatistic/index",
|
||||||
|
"style": { "navigationBarTitleText": "就医统计" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "healthStatistic/index",
|
||||||
|
"style": { "navigationBarTitleText": "档案统计" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "healthScreen/index",
|
||||||
|
"style": { "navigationBarTitleText": "健康总览态势" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "recordScreen/index",
|
||||||
|
"style": { "navigationBarTitleText": "健康档案态势" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "marStatistic/index",
|
||||||
|
"style": { "navigationBarTitleText": "用药统计" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "temperatureStatistic/index",
|
||||||
|
"style": { "navigationBarTitleText": "体温统计" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "milkPowderStatistic/index",
|
||||||
|
"style": { "navigationBarTitleText": "吃奶量统计" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/medicineBasic",
|
||||||
|
"name": "medicineBasic",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": { "navigationBarTitleText": "药品基础信息" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "details",
|
||||||
|
"style": { "navigationBarTitleText": "药品基础信息详情" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "addEdit",
|
||||||
|
"style": { "navigationBarTitleText": "药品基础信息" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/medicineStockIn",
|
||||||
|
"name": "medicineStockIn",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": { "navigationBarTitleText": "药品入库清单" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "details",
|
||||||
|
"style": { "navigationBarTitleText": "药品入库清单详情" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "addEdit",
|
||||||
|
"style": { "navigationBarTitleText": "药品入库清单" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/medicineStock",
|
||||||
|
"name": "medicineStock",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": { "navigationBarTitleText": "药品实时库存" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/medicationPlan",
|
||||||
|
"name": "medicationPlan",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": { "navigationBarTitleText": "用药计划" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "addEdit",
|
||||||
|
"style": { "navigationBarTitleText": "用药计划" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/medicationTask",
|
||||||
|
"name": "medicationTask",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": { "navigationBarTitleText": "服药任务" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/marRecord",
|
||||||
|
"name": "marRecord",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": { "navigationBarTitleText": "用药记录" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "addEdit",
|
||||||
|
"style": { "navigationBarTitleText": "用药记录" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/doctorRecord",
|
||||||
|
"name": "doctorRecord",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": { "navigationBarTitleText": "就医记录" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "addEdit",
|
||||||
|
"style": { "navigationBarTitleText": "就医记录" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "costList",
|
||||||
|
"style": { "navigationBarTitleText": "费用明细" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "costAddEdit",
|
||||||
|
"style": { "navigationBarTitleText": "费用明细" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/healthRecord",
|
||||||
|
"name": "healthRecord",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": { "navigationBarTitleText": "健康档案" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "addEdit",
|
||||||
|
"style": { "navigationBarTitleText": "健康档案" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "details",
|
||||||
|
"style": { "navigationBarTitleText": "档案统计" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/processRecord",
|
||||||
|
"name": "processRecord",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": { "navigationBarTitleText": "档案过程记录" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "addEdit",
|
||||||
|
"style": { "navigationBarTitleText": "过程记录" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"root": "pages/health/chronicDisease",
|
||||||
|
"name": "chronicDisease",
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"path": "list",
|
||||||
|
"style": { "navigationBarTitleText": "慢性疾病档案" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "addEdit",
|
||||||
|
"style": { "navigationBarTitleText": "慢性疾病档案" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "details",
|
||||||
|
"style": { "navigationBarTitleText": "慢性疾病详情" }
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
|
"preloadRule": {
|
||||||
|
"pages/health/index": {
|
||||||
|
"network": "all",
|
||||||
|
"packages": ["medicineBasic", "medicineStockIn", "medicineStock", "medicationPlan", "medicationTask", "marRecord", "doctorRecord", "healthRecord", "processRecord", "chronicDisease"]
|
||||||
|
},
|
||||||
|
"pages/health/statistic/index": {
|
||||||
|
"network": "all",
|
||||||
|
"packages": ["statistic"]
|
||||||
|
}
|
||||||
|
},
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
"color": "#000000",
|
"color": "#000000",
|
||||||
"selectedColor": "#000000",
|
"selectedColor": "#000000",
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="总费用" prop="totalCost" >
|
<u-form-item label="总费用" prop="totalCost" >
|
||||||
<u--input v-model="form.totalCost" type="number" placeholder="请填写总费用"
|
<u--input v-model="form.totalCost" type="digit" placeholder="请填写总费用"
|
||||||
inputAlign="left" :customStyle="getInputStyle('totalCost')">
|
inputAlign="left" :customStyle="getInputStyle('totalCost')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<up-text
|
<up-text
|
||||||
@@ -125,6 +125,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { getActivity, addActivity, updateActivity, uploadFile } from '@/api/health/activity'
|
import { getActivity, addActivity, updateActivity, uploadFile } from '@/api/health/activity'
|
||||||
import config from '@/config'
|
import config from '@/config'
|
||||||
|
import { compressImage } from '@/utils/imageCompress'
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
import { getDicts } from '@/api/system/dict/data.js'
|
import { getDicts } from '@/api/system/dict/data.js'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
@@ -376,38 +377,56 @@ function chooseImage() {
|
|||||||
proxy.$refs['uToast'].show({ message: '正在上传中,请稍候', type: 'warning' })
|
proxy.$refs['uToast'].show({ message: '正在上传中,请稍候', type: 'warning' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// H5 端传 camera 会触发 getUserMedia,可能卡死;微信小程序/APP 需要相机选项
|
||||||
|
let sourceType
|
||||||
|
// #ifdef H5
|
||||||
|
sourceType = ['album']
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
sourceType = ['album', 'camera']
|
||||||
|
// #endif
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
count: 9 - attachmentList.value.length,
|
count: 9 - attachmentList.value.length,
|
||||||
sizeType: ['compressed'],
|
sizeType: ['compressed'],
|
||||||
sourceType: ['album', 'camera'],
|
sourceType,
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
uploadImages(res.tempFilePaths, 0)
|
uploadImages(res.tempFilePaths, 0)
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
// 用户取消选择不走 success,也不会报错,但某些浏览器会触发 fail
|
||||||
|
if (err && err.errMsg && err.errMsg.indexOf('cancel') === -1) {
|
||||||
|
proxy.$refs['uToast'].show({ message: '选择图片失败', type: 'warning' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function uploadImages(paths, index) {
|
async function uploadImages(paths, index) {
|
||||||
if (index >= paths.length) {
|
if (index >= paths.length) {
|
||||||
uploading.value = false
|
uploading.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uploading.value = true
|
uploading.value = true
|
||||||
uni.showLoading({ title: `上传中 ${index + 1}/${paths.length}`, mask: true })
|
uni.showLoading({ title: `处理中 ${index + 1}/${paths.length}`, mask: false })
|
||||||
uploadFile({
|
try {
|
||||||
filePath: paths[index],
|
// 上传前先压缩(超过 500KB 才压,避免小图多走一道)
|
||||||
name: 'file'
|
const compressedPath = await compressImage(paths[index])
|
||||||
}).then(res => {
|
uni.showLoading({ title: `上传中 ${index + 1}/${paths.length}`, mask: false })
|
||||||
|
const res = await uploadFile({
|
||||||
|
filePath: compressedPath,
|
||||||
|
name: 'file'
|
||||||
|
})
|
||||||
const url = (res.data && res.data.url) || res.fileName || res.url
|
const url = (res.data && res.data.url) || res.fileName || res.url
|
||||||
if (url) {
|
if (url) {
|
||||||
attachmentList.value.push(normalizeAttachmentUrl(url))
|
attachmentList.value.push(normalizeAttachmentUrl(url))
|
||||||
}
|
}
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uploadImages(paths, index + 1)
|
uploadImages(paths, index + 1)
|
||||||
}).catch(() => {
|
} catch (e) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uploading.value = false
|
uploading.value = false
|
||||||
proxy.$refs['uToast'].show({ message: `第 ${index + 1} 张上传失败`, type: 'error' })
|
proxy.$refs['uToast'].show({ message: `第 ${index + 1} 张上传失败`, type: 'error' })
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteImage(index) {
|
function deleteImage(index) {
|
||||||
|
|||||||
@@ -103,7 +103,7 @@
|
|||||||
<view class="operate" @click.stop>
|
<view class="operate" @click.stop>
|
||||||
<view class="btn-summary" @click="handleCostSummary(item)">
|
<view class="btn-summary" @click="handleCostSummary(item)">
|
||||||
<uni-icons type="list" size="16" color="#13c2c2"></uni-icons>
|
<uni-icons type="list" size="16" color="#13c2c2"></uni-icons>
|
||||||
<text>费用汇总</text>
|
<text>费用</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="btn-edit" @click="handleEdit(item)">
|
<view class="btn-edit" @click="handleEdit(item)">
|
||||||
<uni-icons type="compose" size="16" color="#667eea"></uni-icons>
|
<uni-icons type="compose" size="16" color="#667eea"></uni-icons>
|
||||||
@@ -454,21 +454,26 @@ function previewAttachment(urls, index) {
|
|||||||
// 活动特有 - 卡片头部布局
|
// 活动特有 - 卡片头部布局
|
||||||
.item-header {
|
.item-header {
|
||||||
gap: 12rpx;
|
gap: 12rpx;
|
||||||
|
/* 允许 header 内容换行,避免长地点/长名字被省略号截断 */
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
.place-info {
|
.place-info {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
|
|
||||||
.place-text {
|
.place-text {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
|
/* 长地点名称最多2行后省略 */
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
word-break: break-all;
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,9 +494,10 @@ function previewAttachment(urls, index) {
|
|||||||
|
|
||||||
.name-section {
|
.name-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
flex: 1;
|
flex: 0 1 auto;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
max-width: 40%;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|
||||||
.name-value {
|
.name-value {
|
||||||
@@ -499,9 +505,13 @@ function previewAttachment(urls, index) {
|
|||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
white-space: nowrap;
|
/* 长活动名最多2行后省略 */
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
word-break: break-all;
|
||||||
|
text-align: right;
|
||||||
letter-spacing: 0.5rpx;
|
letter-spacing: 0.5rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -513,13 +523,6 @@ function previewAttachment(urls, index) {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 活动特有 - 汇总按钮
|
|
||||||
.operate .btn-summary {
|
|
||||||
background: rgba(19, 194, 194, 0.1);
|
|
||||||
color: #13c2c2;
|
|
||||||
border: 1rpx solid rgba(19, 194, 194, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.attachment-list {
|
.attachment-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
</u-form-item>
|
</u-form-item>
|
||||||
|
|
||||||
<u-form-item label="总费用" prop="totalCost" required >
|
<u-form-item label="总费用" prop="totalCost" required >
|
||||||
<u--input v-model="form.totalCost" placeholder="请填写总费用"
|
<u--input v-model="form.totalCost" type="digit" placeholder="请填写总费用"
|
||||||
inputAlign="left" :customStyle="getInputStyle('totalCost')">
|
inputAlign="left" :customStyle="getInputStyle('totalCost')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<up-text
|
<up-text
|
||||||
@@ -114,6 +114,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { getDoctorRecord, addDoctorRecord, updateDoctorRecord, uploadFile } from '@/api/health/doctorRecord'
|
import { getDoctorRecord, addDoctorRecord, updateDoctorRecord, uploadFile } from '@/api/health/doctorRecord'
|
||||||
import config from '@/config'
|
import config from '@/config'
|
||||||
|
import { compressImage } from '@/utils/imageCompress'
|
||||||
import { listPerson } from '@/api/health/person'
|
import { listPerson } from '@/api/health/person'
|
||||||
import { listHealthRecord } from '@/api/health/healthRecord'
|
import { listHealthRecord } from '@/api/health/healthRecord'
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
@@ -171,7 +172,7 @@ rules: {
|
|||||||
hospitalName: [{ required: true, message: '医院名称不能为空', trigger: ['change', 'blur'] }],
|
hospitalName: [{ required: true, message: '医院名称不能为空', trigger: ['change', 'blur'] }],
|
||||||
departments: [{ required: true, message: '科室不能为空', trigger: ['change', 'blur'] }],
|
departments: [{ required: true, message: '科室不能为空', trigger: ['change', 'blur'] }],
|
||||||
doctor: [{ required: true, message: '大夫不能为空', trigger: ['change', 'blur'] }],
|
doctor: [{ required: true, message: '大夫不能为空', trigger: ['change', 'blur'] }],
|
||||||
totalCost: [{ type: 'number', required: true, message: '总费用不能为空', trigger: ['change', 'blur'] }],
|
totalCost: [{ required: true, message: '总费用不能为空', trigger: ['change', 'blur'] }],
|
||||||
partner: [{ required: true, message: '陪同人不能为空', trigger: ['change', 'blur'] }],
|
partner: [{ required: true, message: '陪同人不能为空', trigger: ['change', 'blur'] }],
|
||||||
prescribe: [{ required: true, message: '处理及医嘱不能为空', trigger: ['change', 'blur'] }],
|
prescribe: [{ required: true, message: '处理及医嘱不能为空', trigger: ['change', 'blur'] }],
|
||||||
diagnosis: [{ required: true, message: '诊断结果不能为空', trigger: ['change', 'blur'] }],
|
diagnosis: [{ required: true, message: '诊断结果不能为空', trigger: ['change', 'blur'] }],
|
||||||
@@ -432,39 +433,57 @@ function chooseImage() {
|
|||||||
proxy.$refs['uToast'].show({ message: '正在上传中,请稍候', type: 'warning' })
|
proxy.$refs['uToast'].show({ message: '正在上传中,请稍候', type: 'warning' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// H5 端传 camera 会触发 getUserMedia,可能卡死;微信小程序/APP 需要相机选项
|
||||||
|
let sourceType
|
||||||
|
// #ifdef H5
|
||||||
|
sourceType = ['album']
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
sourceType = ['album', 'camera']
|
||||||
|
// #endif
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
count: 9 - attachmentList.value.length,
|
count: 9 - attachmentList.value.length,
|
||||||
sizeType: ['compressed'],
|
sizeType: ['compressed'],
|
||||||
sourceType: ['album', 'camera'],
|
sourceType,
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
uploadImages(res.tempFilePaths, 0)
|
uploadImages(res.tempFilePaths, 0)
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
// 用户取消选择不走 success,也不会报错,但某些浏览器会触发 fail
|
||||||
|
if (err && err.errMsg && err.errMsg.indexOf('cancel') === -1) {
|
||||||
|
proxy.$refs['uToast'].show({ message: '选择图片失败', type: 'warning' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归上传图片
|
// 递归上传图片
|
||||||
function uploadImages(paths, index) {
|
async function uploadImages(paths, index) {
|
||||||
if (index >= paths.length) {
|
if (index >= paths.length) {
|
||||||
uploading.value = false
|
uploading.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uploading.value = true
|
uploading.value = true
|
||||||
uni.showLoading({ title: `上传中 ${index + 1}/${paths.length}`, mask: true })
|
uni.showLoading({ title: `处理中 ${index + 1}/${paths.length}`, mask: false })
|
||||||
uploadFile({
|
try {
|
||||||
filePath: paths[index],
|
// 上传前先压缩(超过 500KB 才压,避免小图多走一道)
|
||||||
name: 'file'
|
const compressedPath = await compressImage(paths[index])
|
||||||
}).then(res => {
|
uni.showLoading({ title: `上传中 ${index + 1}/${paths.length}`, mask: false })
|
||||||
|
const res = await uploadFile({
|
||||||
|
filePath: compressedPath,
|
||||||
|
name: 'file'
|
||||||
|
})
|
||||||
const url = (res.data && res.data.url) || res.fileName || res.url
|
const url = (res.data && res.data.url) || res.fileName || res.url
|
||||||
if (url) {
|
if (url) {
|
||||||
attachmentList.value.push(normalizeAttachmentUrl(url))
|
attachmentList.value.push(normalizeAttachmentUrl(url))
|
||||||
}
|
}
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uploadImages(paths, index + 1)
|
uploadImages(paths, index + 1)
|
||||||
}).catch(() => {
|
} catch (e) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uploading.value = false
|
uploading.value = false
|
||||||
proxy.$refs['uToast'].show({ message: `第 ${index + 1} 张上传失败`, type: 'error' })
|
proxy.$refs['uToast'].show({ message: `第 ${index + 1} 张上传失败`, type: 'error' })
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除图片
|
// 删除图片
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
<u--input v-model="form.costName" placeholder="请填写费用名称" inputAlign="left" :customStyle="getInputStyle('costName')"></u--input>
|
<u--input v-model="form.costName" placeholder="请填写费用名称" inputAlign="left" :customStyle="getInputStyle('costName')"></u--input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="单价" prop="price" required>
|
<u-form-item label="单价" prop="price" required>
|
||||||
<u--input v-model="form.price" type="number" placeholder="请填写单价" inputAlign="left"
|
<u--input v-model="form.price" type="digit" placeholder="请填写单价" inputAlign="left"
|
||||||
:customStyle="getInputStyle('price')" @change="handlePriceChange">
|
:customStyle="getInputStyle('price')" @change="handlePriceChange">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<up-text text="元"></up-text>
|
<up-text text="元"></up-text>
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
</u--input>
|
</u--input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="数量" prop="count" required>
|
<u-form-item label="数量" prop="count" required>
|
||||||
<u--input v-model="form.count" type="number" placeholder="请填写数量" inputAlign="left"
|
<u--input v-model="form.count" type="digit" placeholder="请填写数量" inputAlign="left"
|
||||||
:customStyle="getInputStyle('count')" @change="handleCountChange"></u--input>
|
:customStyle="getInputStyle('count')" @change="handleCountChange"></u--input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="单位" prop="unitName" required @click="handleUnit">
|
<u-form-item label="单位" prop="unitName" required @click="handleUnit">
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="总价" prop="totalCost" required>
|
<u-form-item label="总价" prop="totalCost" required>
|
||||||
<u--input v-model="form.totalCost" type="number" placeholder="请填写总价" inputAlign="left"
|
<u--input v-model="form.totalCost" type="digit" placeholder="请填写总价" inputAlign="left"
|
||||||
:customStyle="getInputStyle('totalCost')">
|
:customStyle="getInputStyle('totalCost')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<up-text text="元"></up-text>
|
<up-text text="元"></up-text>
|
||||||
|
|||||||
@@ -221,6 +221,35 @@ function handleDelete(item) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildCostDetailSummary() {
|
||||||
|
if (!listData.value.length) return ''
|
||||||
|
|
||||||
|
// 按费用类型分组汇总
|
||||||
|
const groupMap = new Map()
|
||||||
|
listData.value.forEach(item => {
|
||||||
|
const typeKey = item.type || '__other__'
|
||||||
|
const typeLabel = item.type ? (dictStr(item.type, costTypeList.value) || '未分类') : '未分类'
|
||||||
|
if (!groupMap.has(typeKey)) {
|
||||||
|
groupMap.set(typeKey, { label: typeLabel, total: 0, count: 0 })
|
||||||
|
}
|
||||||
|
const g = groupMap.get(typeKey)
|
||||||
|
g.total += Number(item.totalCost || 0)
|
||||||
|
g.count += 1
|
||||||
|
})
|
||||||
|
|
||||||
|
// 拼接汇总字符串,每行一个类型,末行合计
|
||||||
|
const lines = []
|
||||||
|
let grandTotal = 0
|
||||||
|
let grandCount = 0
|
||||||
|
groupMap.forEach(g => {
|
||||||
|
lines.push(`${g.label}:${g.total.toFixed(2)}元(${g.count}笔)`)
|
||||||
|
grandTotal += g.total
|
||||||
|
grandCount += g.count
|
||||||
|
})
|
||||||
|
lines.push(`合计:${grandTotal.toFixed(2)}元(${grandCount}笔)`)
|
||||||
|
return lines.join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
function handleUpdateCost() {
|
function handleUpdateCost() {
|
||||||
if (!doctorRecord.value.id) {
|
if (!doctorRecord.value.id) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -229,15 +258,38 @@ function handleUpdateCost() {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
updateDoctorRecord({
|
if (!listData.value.length) {
|
||||||
...doctorRecord.value,
|
|
||||||
totalCost: Number(detailTotalCost.value)
|
|
||||||
}).then(() => {
|
|
||||||
doctorRecord.value.totalCost = Number(detailTotalCost.value)
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '汇总成功',
|
title: '暂无费用明细,无法汇总',
|
||||||
icon: 'success'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const total = Number(detailTotalCost.value)
|
||||||
|
const costDetail = buildCostDetailSummary()
|
||||||
|
|
||||||
|
// 会覆盖主表原有的费用明细字段,所以弹窗确认
|
||||||
|
uni.showModal({
|
||||||
|
title: '确认汇总',
|
||||||
|
content: `总费用:${total.toFixed(2)}元\n费用明细将按类型汇总并覆盖原有内容,是否继续?`,
|
||||||
|
confirmText: '确认汇总',
|
||||||
|
cancelText: '取消',
|
||||||
|
success: function (res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
updateDoctorRecord({
|
||||||
|
...doctorRecord.value,
|
||||||
|
totalCost: total,
|
||||||
|
costDetail: costDetail
|
||||||
|
}).then(() => {
|
||||||
|
doctorRecord.value.totalCost = total
|
||||||
|
doctorRecord.value.costDetail = costDetail
|
||||||
|
uni.showToast({
|
||||||
|
title: '汇总成功',
|
||||||
|
icon: 'success'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-container">
|
<view class="search-container">
|
||||||
<view class="search-row">
|
<view class="search-row">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -18,8 +18,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view class="add-btn" @click="handleAdd()">
|
<view class="add-btn" @click="handleAdd()">
|
||||||
@@ -28,7 +27,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="search-row">
|
<view class="search-row">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handleHealthRecord">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.healthRecordName"
|
v-model="queryParams.healthRecordName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -43,8 +42,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handleHealthRecord">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
||||||
@@ -63,24 +61,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -284,9 +284,13 @@ onLoad(() => {
|
|||||||
|
|
||||||
|
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function dictStr(val, arr) {
|
function dictStr(val, arr) {
|
||||||
let str = ''
|
let str = ''
|
||||||
arr.map(item => {
|
arr.map(item => {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -17,8 +17,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
||||||
@@ -44,24 +43,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -258,9 +259,13 @@ onLoad(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function loadmore() {
|
function loadmore() {
|
||||||
pageNum.value += 1
|
pageNum.value += 1
|
||||||
if (status.value == 'loadmore') {
|
if (status.value == 'loadmore') {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="身高" required prop="height" >
|
<u-form-item label="身高" required prop="height" >
|
||||||
<u--input v-model="form.height" type="number" placeholder="请填写身高"
|
<u--input v-model="form.height" type="digit" placeholder="请填写身高"
|
||||||
inputAlign="left" :customStyle="getInputStyle('height')">
|
inputAlign="left" :customStyle="getInputStyle('height')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<up-text
|
<up-text
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
</u--input>
|
</u--input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="体重" required prop="weight" >
|
<u-form-item label="体重" required prop="weight" >
|
||||||
<u--input v-model="form.weight" type="number" placeholder="请填写体重过"
|
<u--input v-model="form.weight" type="digit" placeholder="请填写体重过"
|
||||||
inputAlign="left" :customStyle="getInputStyle('weight')">
|
inputAlign="left" :customStyle="getInputStyle('weight')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<up-text
|
<up-text
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -17,8 +17,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
||||||
@@ -39,24 +38,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -190,9 +191,13 @@ onLoad(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function loadmore() {
|
function loadmore() {
|
||||||
pageNum.value += 1
|
pageNum.value += 1
|
||||||
if (status.value == 'loadmore') {
|
if (status.value == 'loadmore') {
|
||||||
|
|||||||
@@ -259,6 +259,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- 悬停按钮返回工作台-->
|
||||||
|
<refresh></refresh>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="用药剂量" prop="dosage" required>
|
<u-form-item label="用药剂量" prop="dosage" required>
|
||||||
<u--input v-model="form.dosage" placeholder="请填写用药剂量"
|
<u--input v-model="form.dosage" placeholder="请填写用药剂量" type="digit"
|
||||||
inputAlign="left" :customStyle="getInputStyle('dosage')"></u--input>
|
inputAlign="left" :customStyle="getInputStyle('dosage')"></u--input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="用药单位" prop="unitName" required @click="handleUnit">
|
<u-form-item label="用药单位" prop="unitName" required @click="handleUnit">
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-container">
|
<view class="search-container">
|
||||||
<view class="search-row">
|
<view class="search-row">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -18,8 +18,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view class="add-btn" @click="handleAdd()">
|
<view class="add-btn" @click="handleAdd()">
|
||||||
@@ -51,8 +50,8 @@
|
|||||||
<view class="filter-panel" :style="{ height: `${windowHeight - 42}px` }">
|
<view class="filter-panel" :style="{ height: `${windowHeight - 42}px` }">
|
||||||
<view class="filter-panel-content">
|
<view class="filter-panel-content">
|
||||||
<view class="filter-title">健康档案</view>
|
<view class="filter-title">健康档案</view>
|
||||||
<view class="health-record-input">
|
<view class="health-record-input" @click="handleHealthRecord">
|
||||||
<u--input v-model="queryParams.healthRecordName" border="surround" type="select" @click="handleHealthRecord" placeholder="请选择健康档案"
|
<u--input v-model="queryParams.healthRecordName" border="surround" type="select" placeholder="请选择健康档案"
|
||||||
suffixIcon="search" suffixIconStyle="color: #909399">
|
suffixIcon="search" suffixIconStyle="color: #909399">
|
||||||
</u--input>
|
</u--input>
|
||||||
</view>
|
</view>
|
||||||
@@ -69,24 +68,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -284,9 +285,13 @@ onLoad(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function loadmore() {
|
function loadmore() {
|
||||||
pageNum.value += 1
|
pageNum.value += 1
|
||||||
if (status.value == 'loadmore') {
|
if (status.value == 'loadmore') {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="每次剂量" prop="dosagePerTime" required>
|
<u-form-item label="每次剂量" prop="dosagePerTime" required>
|
||||||
<view style="display:flex;align-items:center;gap:10rpx;width:100%">
|
<view style="display:flex;align-items:center;gap:10rpx;width:100%">
|
||||||
<u--input v-model="form.dosagePerTime" type="number" placeholder="剂量"
|
<u--input v-model="form.dosagePerTime" type="digit" placeholder="剂量"
|
||||||
inputAlign="left" :customStyle="inputBaseStyle"></u--input>
|
inputAlign="left" :customStyle="inputBaseStyle"></u--input>
|
||||||
<view @click="handleUnitPick" style="min-width:120rpx">
|
<view @click="handleUnitPick" style="min-width:120rpx">
|
||||||
<u--input v-model="form.dosageUnit" readonly disabledColor="#ffffff" placeholder="单位"
|
<u--input v-model="form.dosageUnit" readonly disabledColor="#ffffff" placeholder="单位"
|
||||||
|
|||||||
@@ -177,6 +177,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {getMedicineBasic, addMedicineBasic, updateMedicineBasic, uploadFile } from '@/api/health/medicineBasic'
|
import {getMedicineBasic, addMedicineBasic, updateMedicineBasic, uploadFile } from '@/api/health/medicineBasic'
|
||||||
import config from '@/config'
|
import config from '@/config'
|
||||||
|
import { compressImage } from '@/utils/imageCompress'
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
import { getDicts } from '@/api/system/dict/data.js'
|
import { getDicts } from '@/api/system/dict/data.js'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
@@ -592,28 +593,46 @@ function chooseImage() {
|
|||||||
proxy.$refs['uToast'].show({ message: '正在上传中,请稍候', type: 'warning' })
|
proxy.$refs['uToast'].show({ message: '正在上传中,请稍候', type: 'warning' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// H5 端传 camera 会触发 getUserMedia,可能卡死;微信小程序/APP 需要相机选项
|
||||||
|
let sourceType
|
||||||
|
// #ifdef H5
|
||||||
|
sourceType = ['album']
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
sourceType = ['album', 'camera']
|
||||||
|
// #endif
|
||||||
uni.chooseImage({
|
uni.chooseImage({
|
||||||
count: 9 - attachmentList.value.length,
|
count: 9 - attachmentList.value.length,
|
||||||
sizeType: ['compressed'],
|
sizeType: ['compressed'],
|
||||||
sourceType: ['album', 'camera'],
|
sourceType,
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
uploadImages(res.tempFilePaths, 0)
|
uploadImages(res.tempFilePaths, 0)
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
// 用户取消选择不走 success,也不会报错,但某些浏览器会触发 fail
|
||||||
|
if (err && err.errMsg && err.errMsg.indexOf('cancel') === -1) {
|
||||||
|
proxy.$refs['uToast'].show({ message: '选择图片失败', type: 'warning' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归上传图片
|
// 递归上传图片
|
||||||
function uploadImages(paths, index) {
|
async function uploadImages(paths, index) {
|
||||||
if (index >= paths.length) {
|
if (index >= paths.length) {
|
||||||
uploading.value = false
|
uploading.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uploading.value = true
|
uploading.value = true
|
||||||
uni.showLoading({ title: `上传中 ${index + 1}/${paths.length}`, mask: true })
|
uni.showLoading({ title: `处理中 ${index + 1}/${paths.length}`, mask: false })
|
||||||
uploadFile({
|
try {
|
||||||
filePath: paths[index],
|
// 上传前先压缩(超过 500KB 才压,避免小图多走一道)
|
||||||
name: 'file'
|
const compressedPath = await compressImage(paths[index])
|
||||||
}).then(res => {
|
uni.showLoading({ title: `上传中 ${index + 1}/${paths.length}`, mask: false })
|
||||||
|
const res = await uploadFile({
|
||||||
|
filePath: compressedPath,
|
||||||
|
name: 'file'
|
||||||
|
})
|
||||||
// 打印返回数据,便于调试
|
// 打印返回数据,便于调试
|
||||||
console.log('==== upload response ====', JSON.stringify(res))
|
console.log('==== upload response ====', JSON.stringify(res))
|
||||||
// 兼容多种返回格式
|
// 兼容多种返回格式
|
||||||
@@ -633,11 +652,11 @@ function uploadImages(paths, index) {
|
|||||||
}
|
}
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uploadImages(paths, index + 1)
|
uploadImages(paths, index + 1)
|
||||||
}).catch(() => {
|
} catch (e) {
|
||||||
uni.hideLoading()
|
uni.hideLoading()
|
||||||
uploading.value = false
|
uploading.value = false
|
||||||
proxy.$refs['uToast'].show({ message: `第 ${index + 1} 张上传失败`, type: 'error' })
|
proxy.$refs['uToast'].show({ message: `第 ${index + 1} 张上传失败`, type: 'error' })
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除图片
|
// 删除图片
|
||||||
|
|||||||
@@ -36,24 +36,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -217,8 +219,8 @@ const data = reactive({
|
|||||||
})
|
})
|
||||||
const { filterPanel, queryParams} = toRefs(data)
|
const { filterPanel, queryParams} = toRefs(data)
|
||||||
const windowHeight = computed(() => {
|
const windowHeight = computed(() => {
|
||||||
uni.getSystemInfoSync().windowHeight - 50
|
return uni.getSystemInfoSync().windowHeight - 50
|
||||||
})
|
})
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
getList()
|
getList()
|
||||||
});
|
});
|
||||||
@@ -242,7 +244,7 @@ onLoad(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectType(item) {
|
function selectType(item) {
|
||||||
queryParams.value.type = item.dictValue
|
queryParams.value.treatmentType = item.dictValue
|
||||||
typeList.value.map(ele => {
|
typeList.value.map(ele => {
|
||||||
if (ele.dictValue == item.dictValue) {
|
if (ele.dictValue == item.dictValue) {
|
||||||
ele.selected = true
|
ele.selected = true
|
||||||
@@ -254,9 +256,13 @@ onLoad(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function loadmore() {
|
function loadmore() {
|
||||||
pageNum.value += 1
|
pageNum.value += 1
|
||||||
if (status.value == 'loadmore') {
|
if (status.value == 'loadmore') {
|
||||||
@@ -313,9 +319,12 @@ function settingCancel() {
|
|||||||
settingPickShow.value = false
|
settingPickShow.value = false
|
||||||
}
|
}
|
||||||
function searchSubmit() {
|
function searchSubmit() {
|
||||||
if(queryParams.value.startTime!=''&&queryParams.value.startTime!=undefined&&queryParams.value.endTime!=''&&queryParams.value.endTime!=undefined){
|
// 只有开始和结束时间都设置时才拼接 time 字段,否则清空避免上一次筛选残留
|
||||||
queryParams.value.time = queryParams.value.startTime+'-'+queryParams.value.endTime
|
if (queryParams.value.startTime && queryParams.value.endTime) {
|
||||||
}
|
queryParams.value.time = queryParams.value.startTime + '-' + queryParams.value.endTime
|
||||||
|
} else {
|
||||||
|
queryParams.value.time = ''
|
||||||
|
}
|
||||||
pageNum.value = 1
|
pageNum.value = 1
|
||||||
listData.value = []
|
listData.value = []
|
||||||
getList()
|
getList()
|
||||||
@@ -327,12 +336,15 @@ function settingCancel() {
|
|||||||
getList()
|
getList()
|
||||||
}
|
}
|
||||||
function resetQuery() {
|
function resetQuery() {
|
||||||
queryParams.value.type = ''
|
queryParams.value.treatmentType = ''
|
||||||
queryParams.value.keys = ''
|
queryParams.value.keys = ''
|
||||||
queryParams.value.startTime = ''
|
queryParams.value.startTime = ''
|
||||||
queryParams.value.time = ''
|
queryParams.value.time = ''
|
||||||
|
queryParams.value.endTime = ''
|
||||||
queryParams.value.endTime = ''
|
// 同步重置选中状态
|
||||||
|
typeList.value.forEach(ele => {
|
||||||
|
Reflect.set(ele, 'selected', false)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
function enterDetails(item) {
|
function enterDetails(item) {
|
||||||
uni.navigateTo({ url: `/pages/health/medicineBasic/details?id=${item.id}` })
|
uni.navigateTo({ url: `/pages/health/medicineBasic/details?id=${item.id}` })
|
||||||
|
|||||||
@@ -85,11 +85,11 @@
|
|||||||
inputAlign="left" :customStyle="getInputStyle('ageWeight')"></u--input>
|
inputAlign="left" :customStyle="getInputStyle('ageWeight')"></u--input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="药品单价" prop="purchasePrice" >
|
<u-form-item label="药品单价" prop="purchasePrice" >
|
||||||
<u--input v-model="form.purchasePrice" placeholder="请填写药品单价"
|
<u--input v-model="form.purchasePrice" type="digit" placeholder="请填写药品单价"
|
||||||
inputAlign="left" :customStyle="getInputStyle('purchasePrice')"></u--input>
|
inputAlign="left" :customStyle="getInputStyle('purchasePrice')"></u--input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="药品总价" prop="totalPrice" >
|
<u-form-item label="药品总价" prop="totalPrice" >
|
||||||
<u--input v-model="form.totalPrice" placeholder="请填写药品总价"
|
<u--input v-model="form.totalPrice" type="digit" placeholder="请填写药品总价"
|
||||||
inputAlign="left" :customStyle="getInputStyle('totalPrice')"></u--input>
|
inputAlign="left" :customStyle="getInputStyle('totalPrice')"></u--input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="购买地址" prop="purchaseAddress" labelPosition="top">
|
<u-form-item label="购买地址" prop="purchaseAddress" labelPosition="top">
|
||||||
|
|||||||
@@ -37,24 +37,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -239,9 +241,13 @@ onLoad(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function loadmore() {
|
function loadmore() {
|
||||||
pageNum.value += 1
|
pageNum.value += 1
|
||||||
if (status.value == 'loadmore') {
|
if (status.value == 'loadmore') {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="吃奶量" required prop="consumption" >
|
<u-form-item label="吃奶量" required prop="consumption" >
|
||||||
<u--input v-model="form.consumption" type="number" placeholder="请填写吃奶量"
|
<u--input v-model="form.consumption" type="digit" placeholder="请填写吃奶量"
|
||||||
inputAlign="left" :customStyle="getInputStyle('consumption')">
|
inputAlign="left" :customStyle="getInputStyle('consumption')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<up-text
|
<up-text
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -17,8 +17,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
||||||
@@ -38,24 +37,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -187,9 +188,13 @@ onLoad(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function loadmore() {
|
function loadmore() {
|
||||||
pageNum.value += 1
|
pageNum.value += 1
|
||||||
if (status.value == 'loadmore') {
|
if (status.value == 'loadmore') {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
inputAlign="left" :customStyle="getInputStyle('identityCard')"></u--input>
|
inputAlign="left" :customStyle="getInputStyle('identityCard')"></u--input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="身高" prop="height">
|
<u-form-item label="身高" prop="height">
|
||||||
<u--input v-model="form.height" placeholder="请填写身高" type="number"
|
<u--input v-model="form.height" placeholder="请填写身高" type="digit"
|
||||||
inputAlign="left" :customStyle="getInputStyle('height')">
|
inputAlign="left" :customStyle="getInputStyle('height')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<up-text text="CM"></up-text>
|
<up-text text="CM"></up-text>
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
</u--input>
|
</u--input>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="体重" prop="weight">
|
<u-form-item label="体重" prop="weight">
|
||||||
<u--input v-model="form.weight" placeholder="请填写体重" type="number"
|
<u--input v-model="form.weight" placeholder="请填写体重" type="digit"
|
||||||
inputAlign="left" :customStyle="getInputStyle('weight')">
|
inputAlign="left" :customStyle="getInputStyle('weight')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<up-text text="KG"></up-text>
|
<up-text text="KG"></up-text>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -17,8 +17,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
||||||
@@ -34,9 +33,9 @@
|
|||||||
<view class="filter-panel" :style="{ height: `${windowHeight - 42}px` }">
|
<view class="filter-panel" :style="{ height: `${windowHeight - 42}px` }">
|
||||||
<view class="filter-panel-content">
|
<view class="filter-panel-content">
|
||||||
<view class="filter-title">健康档案</view>
|
<view class="filter-title">健康档案</view>
|
||||||
<view class="health-record-input">
|
<view class="health-record-input" @click="handleHealthRecord">
|
||||||
<u--input v-model="queryParams.healthRecordName" border="surround" placeholder="请选择健康档案"
|
<u--input v-model="queryParams.healthRecordName" border="surround" placeholder="请选择健康档案"
|
||||||
@click="handleHealthRecord" suffixIcon="search" suffixIconStyle="color: #909399">
|
suffixIcon="search" suffixIconStyle="color: #909399">
|
||||||
</u--input>
|
</u--input>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -46,24 +45,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -213,9 +214,13 @@ onLoad(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function loadmore() {
|
function loadmore() {
|
||||||
pageNum.value += 1
|
pageNum.value += 1
|
||||||
if (status.value == 'loadmore') {
|
if (status.value == 'loadmore') {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -17,13 +17,12 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handleHealthRecord">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.healthRecordName"
|
v-model="queryParams.healthRecordName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -38,8 +37,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handleHealthRecord">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -151,24 +149,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -260,7 +260,7 @@
|
|||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
<!-- 曲线图展示 -->
|
<!-- 曲线图展示 -->
|
||||||
<view class="chart-container" v-if="listData.length>0 && viewMode === 'line'">
|
<view class="chart-container" v-if="chartVisible && listData.length>0 && viewMode === 'line'">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
type="line"
|
type="line"
|
||||||
canvasId="doctorLineChart"
|
canvasId="doctorLineChart"
|
||||||
@@ -273,7 +273,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 柱状图展示 -->
|
<!-- 柱状图展示 -->
|
||||||
<view class="chart-container" v-if="listData.length>0 && viewMode === 'column'">
|
<view class="chart-container" v-if="chartVisible && listData.length>0 && viewMode === 'column'">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
type="column"
|
type="column"
|
||||||
canvasId="doctorColumnChart"
|
canvasId="doctorColumnChart"
|
||||||
@@ -803,6 +803,7 @@ const { filterPanel, queryPersonParams, queryHealthRecordParams, queryParams} =
|
|||||||
const windowHeight = computed(() => {
|
const windowHeight = computed(() => {
|
||||||
uni.getSystemInfoSync().windowHeight - 50
|
uni.getSystemInfoSync().windowHeight - 50
|
||||||
})
|
})
|
||||||
|
const chartVisible = computed(() => !filterPanel.value && !timeShow.value && !settingPickShow.value && !showPerson.value && !showHealthRecord.value)
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
getDict()
|
getDict()
|
||||||
// getList()
|
// getList()
|
||||||
@@ -831,9 +832,13 @@ function dictStr(val, arr) {
|
|||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function confirm(e) {
|
function confirm(e) {
|
||||||
const date = timeHandler(new Date(e.value), '-', ':')
|
const date = timeHandler(new Date(e.value), '-', ':')
|
||||||
let formatValue = 'YYYY-MM-DD'
|
let formatValue = 'YYYY-MM-DD'
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="chart-box tall">
|
<view class="chart-box tall">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
v-if="hasChartData(trendChartData)"
|
v-if="chartVisible && hasChartData(trendChartData)"
|
||||||
type="line"
|
type="line"
|
||||||
:canvasId="`${canvasIdPrefix}_trend`"
|
:canvasId="`${canvasIdPrefix}_trend`"
|
||||||
:chartData="trendChartData"
|
:chartData="trendChartData"
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="chart-box">
|
<view class="chart-box">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
v-if="hasChartData(recordChartData)"
|
v-if="chartVisible && hasChartData(recordChartData)"
|
||||||
type="column"
|
type="column"
|
||||||
:canvasId="`${canvasIdPrefix}_record`"
|
:canvasId="`${canvasIdPrefix}_record`"
|
||||||
:chartData="recordChartData"
|
:chartData="recordChartData"
|
||||||
@@ -110,6 +110,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="chart-box">
|
<view class="chart-box">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
|
v-if="chartVisible"
|
||||||
type="ring"
|
type="ring"
|
||||||
:canvasId="`${canvasIdPrefix}_temp_ring`"
|
:canvasId="`${canvasIdPrefix}_temp_ring`"
|
||||||
:chartData="temperatureRingData"
|
:chartData="temperatureRingData"
|
||||||
@@ -136,7 +137,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="chart-box">
|
<view class="chart-box">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
v-if="hasChartData(medicineChartData)"
|
v-if="chartVisible && hasChartData(medicineChartData)"
|
||||||
type="bar"
|
type="bar"
|
||||||
:canvasId="`${canvasIdPrefix}_medicine`"
|
:canvasId="`${canvasIdPrefix}_medicine`"
|
||||||
:chartData="medicineChartData"
|
:chartData="medicineChartData"
|
||||||
@@ -168,7 +169,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="chart-box">
|
<view class="chart-box">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
v-if="hasChartData(doctorCostChartData)"
|
v-if="chartVisible && hasChartData(doctorCostChartData)"
|
||||||
type="column"
|
type="column"
|
||||||
:canvasId="`${canvasIdPrefix}_doctor`"
|
:canvasId="`${canvasIdPrefix}_doctor`"
|
||||||
:chartData="doctorCostChartData"
|
:chartData="doctorCostChartData"
|
||||||
@@ -208,7 +209,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="chart-box">
|
<view class="chart-box">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
v-if="hasChartData(activityChartData)"
|
v-if="chartVisible && hasChartData(activityChartData)"
|
||||||
type="mix"
|
type="mix"
|
||||||
:canvasId="`${canvasIdPrefix}_activity`"
|
:canvasId="`${canvasIdPrefix}_activity`"
|
||||||
:chartData="activityChartData"
|
:chartData="activityChartData"
|
||||||
@@ -288,6 +289,7 @@ const selectedPersonId = ref(null)
|
|||||||
const screenData = ref({})
|
const screenData = ref({})
|
||||||
const dictMap = ref({})
|
const dictMap = ref({})
|
||||||
const canvasIdPrefix = `h5_health_${Date.now()}`
|
const canvasIdPrefix = `h5_health_${Date.now()}`
|
||||||
|
const chartVisible = computed(() => !showPerson.value)
|
||||||
|
|
||||||
const summary = computed(() => screenData.value.summary || {})
|
const summary = computed(() => screenData.value.summary || {})
|
||||||
const record = computed(() => screenData.value.record || {})
|
const record = computed(() => screenData.value.record || {})
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -17,13 +17,12 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handleHealthRecord">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.healthRecordName"
|
v-model="queryParams.healthRecordName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -38,8 +37,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handleHealthRecord">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -216,24 +214,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -264,7 +264,7 @@
|
|||||||
></u-datetime-picker>
|
></u-datetime-picker>
|
||||||
|
|
||||||
<!-- 曲线图展示 -->
|
<!-- 曲线图展示 -->
|
||||||
<view class="chart-container" v-if="secondListData.length>0 && viewMode === 'line'">
|
<view class="chart-container" v-if="chartVisible && secondListData.length>0 && viewMode === 'line'">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
type="line"
|
type="line"
|
||||||
canvasId="healthLineChart"
|
canvasId="healthLineChart"
|
||||||
@@ -277,7 +277,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 柱状图展示 -->
|
<!-- 柱状图展示 -->
|
||||||
<view class="chart-container" v-if="secondListData.length>0 && viewMode === 'column'">
|
<view class="chart-container" v-if="chartVisible && secondListData.length>0 && viewMode === 'column'">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
type="column"
|
type="column"
|
||||||
canvasId="healthColumnChart"
|
canvasId="healthColumnChart"
|
||||||
@@ -657,6 +657,7 @@ const { filterPanel, queryPersonParams,queryHealthRecordParams, queryParams} = t
|
|||||||
const windowHeight = computed(() => {
|
const windowHeight = computed(() => {
|
||||||
uni.getSystemInfoSync().windowHeight - 50
|
uni.getSystemInfoSync().windowHeight - 50
|
||||||
})
|
})
|
||||||
|
const chartVisible = computed(() => !filterPanel.value && !timeShow.value && !settingPickShow.value && !showPerson.value && !showHealthRecord.value)
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
getDict()
|
getDict()
|
||||||
// getList()
|
// getList()
|
||||||
@@ -688,9 +689,13 @@ if (data != null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function confirm(e) {
|
function confirm(e) {
|
||||||
const date = timeHandler(new Date(e.value), '-', ':')
|
const date = timeHandler(new Date(e.value), '-', ':')
|
||||||
let formatValue = 'YYYY-MM-DD'
|
let formatValue = 'YYYY-MM-DD'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -17,13 +17,12 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handleHealthRecord">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.healthRecordName"
|
v-model="queryParams.healthRecordName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -38,8 +37,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handleHealthRecord">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -68,7 +66,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="app-container">
|
<scroll-view class="summary-scroll" scroll-y :style="{ height: summaryScrollHeight }">
|
||||||
|
<view class="app-container">
|
||||||
<view class="header-con" ref="searchHeightRef">
|
<view class="header-con" ref="searchHeightRef">
|
||||||
<view class="item">
|
<view class="item">
|
||||||
<view class="item-icon" style="background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);">
|
<view class="item-icon" style="background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);">
|
||||||
@@ -270,6 +269,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
<!-- 视图切换 -->
|
<!-- 视图切换 -->
|
||||||
<view class="section-title" v-show="listData.length>0">
|
<view class="section-title" v-show="listData.length>0">
|
||||||
@@ -311,24 +311,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -358,7 +360,7 @@
|
|||||||
></u-datetime-picker>
|
></u-datetime-picker>
|
||||||
|
|
||||||
<!-- 曲线图展示 -->
|
<!-- 曲线图展示 -->
|
||||||
<view class="chart-container" v-if="listData.length>0 && viewMode === 'line'">
|
<view class="chart-container" v-if="chartVisible && listData.length>0 && viewMode === 'line'">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
type="line"
|
type="line"
|
||||||
canvasId="marLineChart"
|
canvasId="marLineChart"
|
||||||
@@ -371,7 +373,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 柱状图展示 -->
|
<!-- 柱状图展示 -->
|
||||||
<view class="chart-container" v-if="listData.length>0 && viewMode === 'column'">
|
<view class="chart-container" v-if="chartVisible && listData.length>0 && viewMode === 'column'">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
type="column"
|
type="column"
|
||||||
canvasId="marColumnChart"
|
canvasId="marColumnChart"
|
||||||
@@ -476,6 +478,21 @@ const timeShow= ref(false)
|
|||||||
const time =ref( Number(new Date()))
|
const time =ref( Number(new Date()))
|
||||||
const flag= ref(true)
|
const flag= ref(true)
|
||||||
const mar = ref({})
|
const mar = ref({})
|
||||||
|
const summaryRowCount = computed(() => {
|
||||||
|
const hasValue = (key) => mar.value[key] != null
|
||||||
|
const dynamicRows = [
|
||||||
|
['top2Name', 'top3Name'],
|
||||||
|
['top4Name', 'top5Name'],
|
||||||
|
['top6Name', 'top7Name'],
|
||||||
|
['top8Name', 'top9Name'],
|
||||||
|
['top10Name', 'top11Name'],
|
||||||
|
['top12Name', 'top13Name'],
|
||||||
|
['top14Name', 'top15Name'],
|
||||||
|
['top16Name', 'top17Name']
|
||||||
|
].filter(([left, right]) => hasValue(left) || hasValue(right)).length
|
||||||
|
return 2 + dynamicRows
|
||||||
|
})
|
||||||
|
const summaryScrollHeight = computed(() => `${Math.min(summaryRowCount.value * 120, 480)}rpx`)
|
||||||
|
|
||||||
const tabShow = ref(false)
|
const tabShow = ref(false)
|
||||||
const viewMode = ref('list') // 'list', 'line', 'column'
|
const viewMode = ref('list') // 'list', 'line', 'column'
|
||||||
@@ -687,6 +704,7 @@ const { filterPanel, queryPersonParams,queryHealthRecordParams, queryParams} = t
|
|||||||
const windowHeight = computed(() => {
|
const windowHeight = computed(() => {
|
||||||
uni.getSystemInfoSync().windowHeight - 50
|
uni.getSystemInfoSync().windowHeight - 50
|
||||||
})
|
})
|
||||||
|
const chartVisible = computed(() => !filterPanel.value && !timeShow.value && !settingPickShow.value && !showPerson.value && !showHealthRecord.value)
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
getDict()
|
getDict()
|
||||||
// getList()
|
// getList()
|
||||||
@@ -718,9 +736,13 @@ if (data != null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function confirm(e) {
|
function confirm(e) {
|
||||||
const date = timeHandler(new Date(e.value), '-', ':')
|
const date = timeHandler(new Date(e.value), '-', ':')
|
||||||
let formatValue = 'YYYY-MM-DD'
|
let formatValue = 'YYYY-MM-DD'
|
||||||
@@ -858,6 +880,12 @@ page {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
.summary-scroll {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
flex-shrink: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
.app-container {
|
.app-container {
|
||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -17,8 +17,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -190,24 +189,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -238,7 +239,7 @@
|
|||||||
></u-datetime-picker>
|
></u-datetime-picker>
|
||||||
|
|
||||||
<!-- 曲线图展示 -->
|
<!-- 曲线图展示 -->
|
||||||
<view class="chart-container" v-if="listData.length>0 && viewMode === 'line'">
|
<view class="chart-container" v-if="chartVisible && listData.length>0 && viewMode === 'line'">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
type="line"
|
type="line"
|
||||||
canvasId="milkLineChart"
|
canvasId="milkLineChart"
|
||||||
@@ -251,7 +252,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 柱状图展示 -->
|
<!-- 柱状图展示 -->
|
||||||
<view class="chart-container" v-if="listData.length>0 && viewMode === 'column'">
|
<view class="chart-container" v-if="chartVisible && listData.length>0 && viewMode === 'column'">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
type="column"
|
type="column"
|
||||||
canvasId="milkColumnChart"
|
canvasId="milkColumnChart"
|
||||||
@@ -519,6 +520,7 @@ const { filterPanel, queryPersonParams, queryParams} = toRefs(data)
|
|||||||
const windowHeight = computed(() => {
|
const windowHeight = computed(() => {
|
||||||
uni.getSystemInfoSync().windowHeight - 50
|
uni.getSystemInfoSync().windowHeight - 50
|
||||||
})
|
})
|
||||||
|
const chartVisible = computed(() => !filterPanel.value && !timeShow.value && !settingPickShow.value && !showPerson.value)
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
getDict()
|
getDict()
|
||||||
// getList()
|
// getList()
|
||||||
@@ -538,9 +540,13 @@ if (data != null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function confirm(e) {
|
function confirm(e) {
|
||||||
const date = timeHandler(new Date(e.value), '-', ':')
|
const date = timeHandler(new Date(e.value), '-', ':')
|
||||||
let formatValue = 'YYYY-MM-DD'
|
let formatValue = 'YYYY-MM-DD'
|
||||||
|
|||||||
@@ -95,7 +95,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="chart-box tall">
|
<view class="chart-box tall">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
v-if="hasChartData(temperatureChartData)"
|
v-if="chartVisible && hasChartData(temperatureChartData)"
|
||||||
type="line"
|
type="line"
|
||||||
:canvasId="`${canvasIdPrefix}_temp`"
|
:canvasId="`${canvasIdPrefix}_temp`"
|
||||||
:chartData="temperatureChartData"
|
:chartData="temperatureChartData"
|
||||||
@@ -117,6 +117,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="chart-box">
|
<view class="chart-box">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
|
v-if="chartVisible"
|
||||||
type="ring"
|
type="ring"
|
||||||
:canvasId="`${canvasIdPrefix}_mix`"
|
:canvasId="`${canvasIdPrefix}_mix`"
|
||||||
:chartData="recordMixChartData"
|
:chartData="recordMixChartData"
|
||||||
@@ -152,7 +153,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="chart-box">
|
<view class="chart-box">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
v-if="hasChartData(medicineChartData)"
|
v-if="chartVisible && hasChartData(medicineChartData)"
|
||||||
type="bar"
|
type="bar"
|
||||||
:canvasId="`${canvasIdPrefix}_medicine`"
|
:canvasId="`${canvasIdPrefix}_medicine`"
|
||||||
:chartData="medicineChartData"
|
:chartData="medicineChartData"
|
||||||
@@ -184,7 +185,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="chart-box">
|
<view class="chart-box">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
v-if="hasChartData(doctorCostChartData)"
|
v-if="chartVisible && hasChartData(doctorCostChartData)"
|
||||||
type="column"
|
type="column"
|
||||||
:canvasId="`${canvasIdPrefix}_doctor`"
|
:canvasId="`${canvasIdPrefix}_doctor`"
|
||||||
:chartData="doctorCostChartData"
|
:chartData="doctorCostChartData"
|
||||||
@@ -293,6 +294,7 @@ const screenData = ref({})
|
|||||||
const activeTab = ref('process')
|
const activeTab = ref('process')
|
||||||
const dictMap = ref({})
|
const dictMap = ref({})
|
||||||
const canvasIdPrefix = `h5_record_${Date.now()}`
|
const canvasIdPrefix = `h5_record_${Date.now()}`
|
||||||
|
const chartVisible = computed(() => !showPerson.value && !showRecord.value)
|
||||||
|
|
||||||
const record = computed(() => screenData.value.record || {})
|
const record = computed(() => screenData.value.record || {})
|
||||||
const summary = computed(() => screenData.value.summary || {})
|
const summary = computed(() => screenData.value.summary || {})
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="container">
|
<view class="container">
|
||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -17,13 +17,12 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="search-view">
|
<view class="search-view">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handleHealthRecord">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.healthRecordName"
|
v-model="queryParams.healthRecordName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -38,8 +37,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handleHealthRecord">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -192,24 +190,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -240,7 +240,7 @@
|
|||||||
></u-datetime-picker>
|
></u-datetime-picker>
|
||||||
|
|
||||||
<!-- 曲线图展示 -->
|
<!-- 曲线图展示 -->
|
||||||
<view class="chart-container" v-if="hasSecondListData && viewMode === 'line'">
|
<view class="chart-container" v-if="chartVisible && hasSecondListData && viewMode === 'line'">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
type="line"
|
type="line"
|
||||||
:canvasId="canvasIdPrefix + '_line'"
|
:canvasId="canvasIdPrefix + '_line'"
|
||||||
@@ -253,7 +253,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 柱状图展示 -->
|
<!-- 柱状图展示 -->
|
||||||
<view class="chart-container" v-if="hasSecondListData && viewMode === 'column'">
|
<view class="chart-container" v-if="chartVisible && hasSecondListData && viewMode === 'column'">
|
||||||
<qiun-data-charts
|
<qiun-data-charts
|
||||||
type="column"
|
type="column"
|
||||||
:canvasId="canvasIdPrefix + '_column'"
|
:canvasId="canvasIdPrefix + '_column'"
|
||||||
@@ -634,6 +634,7 @@ uni.getSystemInfo({
|
|||||||
windowHeight.value = res.windowHeight - 50
|
windowHeight.value = res.windowHeight - 50
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const chartVisible = computed(() => !filterPanel.value && !timeShow.value && !settingPickShow.value && !showPerson.value && !showHealthRecord.value)
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
getDict()
|
getDict()
|
||||||
// getList()
|
// getList()
|
||||||
@@ -666,9 +667,13 @@ if (data != null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function confirm(e) {
|
function confirm(e) {
|
||||||
const date = timeHandler(new Date(e.value), '-', ':')
|
const date = timeHandler(new Date(e.value), '-', ':')
|
||||||
let formatValue = 'YYYY-MM-DD'
|
let formatValue = 'YYYY-MM-DD'
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</u-form-item>
|
</u-form-item>
|
||||||
<u-form-item label="体温" required prop="temperature" >
|
<u-form-item label="体温" required prop="temperature" >
|
||||||
<u--input v-model="form.temperature" type="number" placeholder="请填写体温"
|
<u--input v-model="form.temperature" type="digit" placeholder="请填写体温"
|
||||||
inputAlign="left" :customStyle="getInputStyle('temperature')">
|
inputAlign="left" :customStyle="getInputStyle('temperature')">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<up-text
|
<up-text
|
||||||
@@ -103,7 +103,7 @@ queryHealthRecordParams: {
|
|||||||
rules: {
|
rules: {
|
||||||
healthRecordName: [{ required: true, message: '健康档案不能为空', trigger:['change', 'blur'] }],
|
healthRecordName: [{ required: true, message: '健康档案不能为空', trigger:['change', 'blur'] }],
|
||||||
personName: [{ required: true, message: '人员不能为空', trigger: ['change', 'blur'] }],
|
personName: [{ required: true, message: '人员不能为空', trigger: ['change', 'blur'] }],
|
||||||
temperature: [{ type: 'number',required: true, message: '体温不能为空', trigger: ['change', 'blur'] }],
|
temperature: [{ required: true, message: '体温不能为空', trigger: ['change', 'blur'] }],
|
||||||
measureTime: [{ required: true, message: '测量时间不能为空', trigger: ['change', 'blur'] }]
|
measureTime: [{ required: true, message: '测量时间不能为空', trigger: ['change', 'blur'] }]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
<u-sticky offsetTop="0rpx" customNavHeight="0rpx">
|
||||||
<view class="search-container">
|
<view class="search-container">
|
||||||
<view class="search-row">
|
<view class="search-row">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handlePerson">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.personName"
|
v-model="queryParams.personName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -18,8 +18,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handlePerson">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view class="add-btn" @click="handleAdd()">
|
<view class="add-btn" @click="handleAdd()">
|
||||||
@@ -28,7 +27,7 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="search-row">
|
<view class="search-row">
|
||||||
<view class="search-input-wrapper">
|
<view class="search-input-wrapper" @click="handleHealthRecord">
|
||||||
<u--input
|
<u--input
|
||||||
v-model="queryParams.healthRecordName"
|
v-model="queryParams.healthRecordName"
|
||||||
border="surround"
|
border="surround"
|
||||||
@@ -43,8 +42,7 @@
|
|||||||
type="search"
|
type="search"
|
||||||
size="18"
|
size="18"
|
||||||
color="#667eea"
|
color="#667eea"
|
||||||
class="search-icon"
|
class="search-icon">
|
||||||
@click="handleHealthRecord">
|
|
||||||
</uni-icons>
|
</uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
<view class="filter-btn" @click="filterPanel = !filterPanel">
|
||||||
@@ -63,24 +61,26 @@
|
|||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(true)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.startTime"
|
v-model="queryParams.startTime"
|
||||||
placeholder="请选择开始时间"
|
placeholder="请选择开始时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(true)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(true)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
<u-input
|
<u-input
|
||||||
:disabled="true"
|
:disabled="true"
|
||||||
:disabledColor="'#fff'"
|
:disabledColor="'#fff'"
|
||||||
class="dateInput"
|
class="dateInput"
|
||||||
|
@click="openOrCloseDate(false)"
|
||||||
border="surround"
|
border="surround"
|
||||||
v-model="queryParams.endTime"
|
v-model="queryParams.endTime"
|
||||||
placeholder="请选择结束时间"
|
placeholder="请选择结束时间"
|
||||||
>
|
>
|
||||||
<template v-slot:suffix>
|
<template v-slot:suffix>
|
||||||
<u-icon name="calendar" @click="openOrCloseDate(false)"></u-icon>
|
<u-icon name="calendar" @click.stop="openOrCloseDate(false)"></u-icon>
|
||||||
</template>
|
</template>
|
||||||
</u-input>
|
</u-input>
|
||||||
</view>
|
</view>
|
||||||
@@ -227,9 +227,13 @@ onLoad(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
function openOrCloseDate(data) {
|
function openOrCloseDate(data) {
|
||||||
timeShow.value = !timeShow.value
|
if (typeof data === 'boolean') {
|
||||||
flag.value = data
|
flag.value = data
|
||||||
|
timeShow.value = true
|
||||||
|
} else {
|
||||||
|
timeShow.value = false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function loadmore() {
|
function loadmore() {
|
||||||
pageNum.value += 1
|
pageNum.value += 1
|
||||||
if (status.value == 'loadmore') {
|
if (status.value == 'loadmore') {
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="login-container">
|
<view v-if="checkingToken" class="token-transition-screen">
|
||||||
|
<view class="token-loading-card">
|
||||||
|
<view class="token-loading-spinner"></view>
|
||||||
|
<text class="token-loading-text">正在加载中...</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view v-else class="login-container">
|
||||||
<!-- Logo和标题区域 -->
|
<!-- Logo和标题区域 -->
|
||||||
<view class="header-section">
|
<view class="header-section">
|
||||||
<view class="logo-box">
|
<view class="logo-box">
|
||||||
@@ -69,7 +76,7 @@
|
|||||||
|
|
||||||
<!-- 版权信息 -->
|
<!-- 版权信息 -->
|
||||||
<view class="copyright">
|
<view class="copyright">
|
||||||
<text>Copyright © 2026 qdintc All Rights Reserved.</text>
|
<text>Copyright © {{ currentYear }} qdintc All Rights Reserved.</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -82,9 +89,12 @@ import config from '@/config.js'
|
|||||||
import useUserStore from '@/store/modules/user'
|
import useUserStore from '@/store/modules/user'
|
||||||
import { getWxCode } from '@/utils/geek';
|
import { getWxCode } from '@/utils/geek';
|
||||||
import { wxLogin } from '@/api/oauth';
|
import { wxLogin } from '@/api/oauth';
|
||||||
import { setToken } from '@/utils/auth';
|
import { getToken, setToken } from '@/utils/auth';
|
||||||
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
import { encrypt, decrypt } from '@/utils/jsencrypt'
|
||||||
|
|
||||||
|
// 动态显示当前年份
|
||||||
|
const currentYear = new Date().getFullYear()
|
||||||
|
|
||||||
// ========== 平台判断(条件编译)==========
|
// ========== 平台判断(条件编译)==========
|
||||||
// H5 端为 true,其他端为 false。条件编译保证仅 H5 打包对应逻辑
|
// H5 端为 true,其他端为 false。条件编译保证仅 H5 打包对应逻辑
|
||||||
let isH5 = false
|
let isH5 = false
|
||||||
@@ -101,6 +111,7 @@ const useWxLogin = ref(false); // 是否使用微信登录
|
|||||||
const globalConfig = ref(config);
|
const globalConfig = ref(config);
|
||||||
const agree = ref(isH5 ? true : false); // H5 端默认勾选同意协议
|
const agree = ref(isH5 ? true : false); // H5 端默认勾选同意协议
|
||||||
const rememberPwd = ref(false); // 记住密码
|
const rememberPwd = ref(false); // 记住密码
|
||||||
|
const checkingToken = ref(true); // 是否正在校验本地 token
|
||||||
const loginForm = ref({
|
const loginForm = ref({
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
@@ -119,11 +130,36 @@ if (useWxLogin.value) {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 页面加载时检查是否记住了密码
|
// 页面加载时先校验本地 token,仍有效则直接进入系统;无效时再显示账号密码登录
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadRememberedLogin()
|
initLoginPage()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function initLoginPage() {
|
||||||
|
const token = getToken()
|
||||||
|
if (token) {
|
||||||
|
checkingToken.value = true
|
||||||
|
let tokenValid = false
|
||||||
|
try {
|
||||||
|
await userStore.getInfo(true)
|
||||||
|
tokenValid = true
|
||||||
|
} catch (error) {
|
||||||
|
if (error && error.code === 401) {
|
||||||
|
userStore.resetToken()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokenValid) {
|
||||||
|
goHome()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkingToken.value = false
|
||||||
|
loadRememberedLogin()
|
||||||
|
getCode()
|
||||||
|
}
|
||||||
|
|
||||||
// 读取本地记住的登录信息(仅 H5)
|
// 读取本地记住的登录信息(仅 H5)
|
||||||
function loadRememberedLogin() {
|
function loadRememberedLogin() {
|
||||||
if (!isH5) return
|
if (!isH5) return
|
||||||
@@ -209,12 +245,16 @@ async function pwdLogin() {
|
|||||||
function loginSuccess(result) {
|
function loginSuccess(result) {
|
||||||
// 设置用户信息
|
// 设置用户信息
|
||||||
userStore.getInfo().then(res => {
|
userStore.getInfo().then(res => {
|
||||||
uni.switchTab({
|
goHome()
|
||||||
url: '/pages/health/homepage/index'
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goHome() {
|
||||||
|
uni.switchTab({
|
||||||
|
url: '/pages/health/homepage/index'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function agreeChange(){
|
function agreeChange(){
|
||||||
agree.value = !agree.value;
|
agree.value = !agree.value;
|
||||||
}
|
}
|
||||||
@@ -244,7 +284,6 @@ function handleUserAgrement() {
|
|||||||
url: '/pages/common/agreement/index'
|
url: '/pages/common/agreement/index'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
getCode();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -262,6 +301,55 @@ page {
|
|||||||
padding: 0 48rpx;
|
padding: 0 48rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.token-transition-screen {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: linear-gradient(160deg, #FFF3D6 0%, #FFE0A0 60%, #FFCC6E 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.token-loading-card {
|
||||||
|
min-width: 220rpx;
|
||||||
|
min-height: 180rpx;
|
||||||
|
padding: 40rpx 48rpx;
|
||||||
|
border-radius: 32rpx;
|
||||||
|
background: rgba(255, 255, 255, 0.72);
|
||||||
|
border: 1rpx solid rgba(255, 255, 255, 0.7);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 16rpx 48rpx rgba(139, 69, 0, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.token-loading-spinner {
|
||||||
|
width: 58rpx;
|
||||||
|
height: 58rpx;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 6rpx solid rgba(232, 132, 26, 0.2);
|
||||||
|
border-top-color: #E8841A;
|
||||||
|
animation: token-loading-spin 0.8s linear infinite;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token-loading-text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #8B4500;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes token-loading-spin {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.header-section {
|
.header-section {
|
||||||
padding-top: 120rpx;
|
padding-top: 120rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -37,12 +37,22 @@
|
|||||||
</view>
|
</view>
|
||||||
<text class="action-text">交流社区</text>
|
<text class="action-text">交流社区</text>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<button class="action-card action-button" open-type="contact" @contact="handleContact">
|
||||||
|
<view class="action-icon" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
|
||||||
|
<uni-icons type="contact" size="24" color="#ffffff"></uni-icons>
|
||||||
|
</view>
|
||||||
|
<text class="action-text">联系客服</text>
|
||||||
|
</button>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef MP-WEIXIN -->
|
||||||
<view class="action-card" @click="handleService">
|
<view class="action-card" @click="handleService">
|
||||||
<view class="action-icon" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
|
<view class="action-icon" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
|
||||||
<uni-icons type="contact" size="24" color="#ffffff"></uni-icons>
|
<uni-icons type="contact" size="24" color="#ffffff"></uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<text class="action-text">联系客服</text>
|
<text class="action-text">联系客服</text>
|
||||||
</view>
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
<view class="action-card" @click="handleBuilding">
|
<view class="action-card" @click="handleBuilding">
|
||||||
<view class="action-icon" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);">
|
<view class="action-icon" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);">
|
||||||
<uni-icons type="compose" size="24" color="#ffffff"></uni-icons>
|
<uni-icons type="compose" size="24" color="#ffffff"></uni-icons>
|
||||||
@@ -53,7 +63,7 @@
|
|||||||
<view class="action-icon" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);">
|
<view class="action-icon" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);">
|
||||||
<uni-icons type="star" size="24" color="#ffffff"></uni-icons>
|
<uni-icons type="star" size="24" color="#ffffff"></uni-icons>
|
||||||
</view>
|
</view>
|
||||||
<text class="action-text">给个好评</text>
|
<text class="action-text">支持我们</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -134,6 +144,9 @@ const userStore = useUserStore()
|
|||||||
const name = userStore.name;
|
const name = userStore.name;
|
||||||
const userId = computed(() => userStore.userId || '');
|
const userId = computed(() => userStore.userId || '');
|
||||||
const version = config.appInfo.version;
|
const version = config.appInfo.version;
|
||||||
|
const communityWechat = 'intc126';
|
||||||
|
const servicePhone = '17753252359';
|
||||||
|
const officialSite = config.appInfo.site_url;
|
||||||
|
|
||||||
const popup = ref(null);
|
const popup = ref(null);
|
||||||
function handleToInfo() {
|
function handleToInfo() {
|
||||||
@@ -182,35 +195,73 @@ function handleAbout() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
function handleJiaoLiuQun() {
|
function handleJiaoLiuQun() {
|
||||||
uni.showToast({
|
uni.showModal({
|
||||||
title: 'intc126',
|
title: '加入交流群',
|
||||||
mask: false,
|
content: `复制微信号 ${communityWechat},添加后备注“智聪网络科技”,获取使用交流、问题答疑和功能更新。`,
|
||||||
icon: "none",
|
confirmText: '复制微信号',
|
||||||
duration: 5000
|
cancelText: '稍后再说',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
copyText(communityWechat, '微信号已复制');
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
function handleBuilding() {
|
function handleBuilding() {
|
||||||
uni.showToast({
|
uni.navigateTo({
|
||||||
title: '谢谢反馈~',
|
url: '/pages_mine/pages/feedback/index'
|
||||||
mask: false,
|
|
||||||
icon: "none",
|
|
||||||
duration: 1000
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function handleService() {
|
function handleService() {
|
||||||
uni.showToast({
|
uni.showActionSheet({
|
||||||
title: '请电联或加客服微信:17753252359',
|
itemList: ['拨打客服电话', '复制客服微信', '查看关于我们'],
|
||||||
mask: false,
|
success: ({ tapIndex }) => {
|
||||||
icon: "none",
|
if (tapIndex === 0) {
|
||||||
duration: 5000
|
uni.makePhoneCall({ phoneNumber: servicePhone });
|
||||||
|
} else if (tapIndex === 1) {
|
||||||
|
copyText(servicePhone, '客服微信已复制');
|
||||||
|
} else if (tapIndex === 2) {
|
||||||
|
handleAbout();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function handleContact() {
|
||||||
|
// 微信小程序端由 open-type="contact" 直接打开原生客服会话
|
||||||
|
}
|
||||||
function handleUs() {
|
function handleUs() {
|
||||||
uni.showToast({
|
uni.showActionSheet({
|
||||||
title: '谢谢点赞!',
|
itemList: ['推荐给朋友', '复制官网链接', '意见反馈'],
|
||||||
mask: false,
|
success: ({ tapIndex }) => {
|
||||||
icon: "none",
|
if (tapIndex === 0) {
|
||||||
duration: 1000
|
uni.showModal({
|
||||||
|
title: '感谢支持',
|
||||||
|
content: '如果觉得好用,可以点击右上角“···”分享给朋友,也欢迎把官网链接发给需要的人。',
|
||||||
|
confirmText: '复制官网',
|
||||||
|
cancelText: '知道了',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm) {
|
||||||
|
copyText(officialSite, '官网链接已复制');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (tapIndex === 1) {
|
||||||
|
copyText(officialSite, '官网链接已复制');
|
||||||
|
} else if (tapIndex === 2) {
|
||||||
|
handleBuilding();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function copyText(data, title = '复制成功') {
|
||||||
|
uni.setClipboardData({
|
||||||
|
data,
|
||||||
|
success: () => {
|
||||||
|
uni.showToast({
|
||||||
|
title,
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -403,6 +454,18 @@ page {
|
|||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-button {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-section {
|
.menu-section {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="footer-section">
|
<view class="footer-section">
|
||||||
<text class="copyright-text">Copyright © 2026 qdintc All Rights Reserved.</text>
|
<text class="copyright-text">Copyright © {{ currentYear }} qdintc All Rights Reserved.</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<u-toast ref="uToast"></u-toast>
|
<u-toast ref="uToast"></u-toast>
|
||||||
@@ -72,6 +72,8 @@
|
|||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
// 动态显示当前年份
|
||||||
|
currentYear: new Date().getFullYear(),
|
||||||
user: {
|
user: {
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="about-container">
|
<view class="about-container">
|
||||||
<view class="header-section">
|
<view class="header-section">
|
||||||
<view class="logo-wrapper">
|
<view class="logo-wrapper">
|
||||||
<image class="logo-image" src="/static/logo.png" mode="aspectFit"></image>
|
<image class="logo-image" src="/static/logo1.png" mode="aspectFit"></image>
|
||||||
<view class="logo-shine"></view>
|
<view class="logo-shine"></view>
|
||||||
</view>
|
</view>
|
||||||
<text class="app-name">智聪网络科技</text>
|
<text class="app-name">智聪网络科技</text>
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="copyright">
|
<view class="copyright">
|
||||||
<text class="copyright-text">Copyright © 2026 qdintc</text>
|
<text class="copyright-text">Copyright © {{ currentYear }} qdintc</text>
|
||||||
<text class="copyright-text">All Rights Reserved.</text>
|
<text class="copyright-text">All Rights Reserved.</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -36,7 +36,25 @@ import { computed } from 'vue'
|
|||||||
import config from '@/config.js'
|
import config from '@/config.js'
|
||||||
|
|
||||||
const url = config.appInfo.site_url
|
const url = config.appInfo.site_url
|
||||||
const version = config.appInfo.version
|
// 动态获取版本号
|
||||||
|
// - 微信小程序:优先读取小程序后台提交发布时填写的版本号,为空时回退到 config
|
||||||
|
// 注:在微信开发者工具中调用时 miniProgram.version 通常为空字符串,
|
||||||
|
// 只有体验版/正式版发布后才有真实值
|
||||||
|
// - 其他端(H5/APP):使用 config 中的版本号
|
||||||
|
let version = config.appInfo.version
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
try {
|
||||||
|
const accountInfo = uni.getAccountInfoSync()
|
||||||
|
const mpVersion = accountInfo && accountInfo.miniProgram && accountInfo.miniProgram.version
|
||||||
|
if (mpVersion) {
|
||||||
|
version = mpVersion
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('getAccountInfoSync 调用失败,使用 config 中的版本号:', e)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// 动态显示当前年份
|
||||||
|
const currentYear = new Date().getFullYear()
|
||||||
|
|
||||||
const infoList = computed(() => [
|
const infoList = computed(() => [
|
||||||
{
|
{
|
||||||
|
|||||||
417
src/pages_mine/pages/feedback/index.vue
Normal file
417
src/pages_mine/pages/feedback/index.vue
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
<template>
|
||||||
|
<view class="feedback-container">
|
||||||
|
<view class="intro-card">
|
||||||
|
<view class="intro-icon">
|
||||||
|
<uni-icons type="compose" size="28" color="#ffffff"></uni-icons>
|
||||||
|
</view>
|
||||||
|
<view class="intro-content">
|
||||||
|
<text class="intro-title">意见反馈</text>
|
||||||
|
<text class="intro-desc">请描述遇到的问题或功能建议。</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="form-card">
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="label">反馈类型</text>
|
||||||
|
<picker mode="selector" :range="feedbackTypes" :value="feedbackTypeIndex" @change="handleTypeChange">
|
||||||
|
<view class="picker-row">
|
||||||
|
<text>{{ currentType }}</text>
|
||||||
|
<uni-icons type="right" size="16" color="#c0c4cc"></uni-icons>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="label required">反馈内容</text>
|
||||||
|
<textarea
|
||||||
|
v-model="content"
|
||||||
|
class="content-input"
|
||||||
|
maxlength="500"
|
||||||
|
placeholder="请尽量说明操作步骤、看到的问题或希望增加的功能"
|
||||||
|
placeholder-class="placeholder"
|
||||||
|
/>
|
||||||
|
<text class="count-text">{{ content.length }}/500</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="form-item">
|
||||||
|
<text class="label">联系方式</text>
|
||||||
|
<input
|
||||||
|
v-model="contact"
|
||||||
|
class="contact-input"
|
||||||
|
maxlength="100"
|
||||||
|
placeholder="选填,便于客服进一步沟通"
|
||||||
|
placeholder-class="placeholder"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="form-item">
|
||||||
|
<view class="label-row">
|
||||||
|
<text class="label">截图</text>
|
||||||
|
<text class="tip-text">选填,最多 3 张</text>
|
||||||
|
</view>
|
||||||
|
<view class="image-list">
|
||||||
|
<view v-for="(image, index) in imageList" :key="image" class="image-item">
|
||||||
|
<image :src="image" mode="aspectFill"></image>
|
||||||
|
<view class="remove-image" @click="removeImage(index)">
|
||||||
|
<uni-icons type="closeempty" size="18" color="#ffffff"></uni-icons>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="imageList.length < 3" class="add-image" @click="chooseImages">
|
||||||
|
<uni-icons type="plusempty" size="28" color="#909399"></uni-icons>
|
||||||
|
<text>添加截图</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="submit-section">
|
||||||
|
<button class="submit-btn" :loading="submitting" :disabled="submitting" @click="handleSubmit">
|
||||||
|
{{ submitting ? '提交中...' : '提交反馈' }}
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import appConfig from '@/config'
|
||||||
|
import { submitFeedback, uploadFeedbackImage } from '@/api/system/feedback'
|
||||||
|
|
||||||
|
const feedbackTypes = ['功能建议', '问题反馈', '数据异常', '其他']
|
||||||
|
const feedbackTypeIndex = ref(0)
|
||||||
|
const content = ref('')
|
||||||
|
const contact = ref('')
|
||||||
|
const imageList = ref([])
|
||||||
|
const submitting = ref(false)
|
||||||
|
const serviceWechat = '17753252359'
|
||||||
|
|
||||||
|
const currentType = computed(() => feedbackTypes[feedbackTypeIndex.value])
|
||||||
|
|
||||||
|
function handleTypeChange(e) {
|
||||||
|
feedbackTypeIndex.value = Number(e.detail.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function chooseImages() {
|
||||||
|
const restCount = 3 - imageList.value.length
|
||||||
|
if (restCount <= 0 || submitting.value) return
|
||||||
|
|
||||||
|
uni.chooseImage({
|
||||||
|
count: restCount,
|
||||||
|
sizeType: ['compressed'],
|
||||||
|
success: (res) => {
|
||||||
|
imageList.value = imageList.value.concat(res.tempFilePaths || []).slice(0, 3)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeImage(index) {
|
||||||
|
if (submitting.value) return
|
||||||
|
imageList.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
if (submitting.value) return
|
||||||
|
|
||||||
|
const feedbackContent = content.value.trim()
|
||||||
|
if (!feedbackContent) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请先填写反馈内容',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
submitting.value = true
|
||||||
|
uni.showLoading({ title: imageList.value.length ? '上传截图中...' : '提交中...' })
|
||||||
|
|
||||||
|
try {
|
||||||
|
const imageUrls = await uploadImages(imageList.value)
|
||||||
|
uni.showLoading({ title: '提交中...' })
|
||||||
|
|
||||||
|
await submitFeedback({
|
||||||
|
feedbackType: currentType.value,
|
||||||
|
content: feedbackContent,
|
||||||
|
contact: contact.value.trim(),
|
||||||
|
images: imageUrls.join(','),
|
||||||
|
source: getFeedbackSource()
|
||||||
|
})
|
||||||
|
|
||||||
|
content.value = ''
|
||||||
|
contact.value = ''
|
||||||
|
imageList.value = []
|
||||||
|
feedbackTypeIndex.value = 0
|
||||||
|
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showModal({
|
||||||
|
title: '提交成功',
|
||||||
|
content: '您的反馈已提交,我们会尽快处理。',
|
||||||
|
confirmText: '知道了',
|
||||||
|
showCancel: false
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
uni.hideLoading()
|
||||||
|
if (error !== '500') {
|
||||||
|
uni.showToast({
|
||||||
|
title: '提交失败,请稍后重试',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function uploadImages(paths) {
|
||||||
|
const urls = []
|
||||||
|
for (const path of paths) {
|
||||||
|
const uploadRes = await uploadFeedbackImage(path)
|
||||||
|
urls.push(normalizeUploadUrl(uploadRes))
|
||||||
|
}
|
||||||
|
return urls
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeUploadUrl(uploadRes) {
|
||||||
|
const data = uploadRes?.data || {}
|
||||||
|
const url = data.url || data.fileName || uploadRes?.url || uploadRes?.fileName || uploadRes?.imgUrl
|
||||||
|
if (!url) {
|
||||||
|
throw new Error('上传截图失败')
|
||||||
|
}
|
||||||
|
let finalUrl
|
||||||
|
if (/^https?:\/\//.test(url)) {
|
||||||
|
finalUrl = url
|
||||||
|
} else {
|
||||||
|
finalUrl = `${appConfig.baseUrl}${url.startsWith('/') ? '' : '/'}${url}`
|
||||||
|
}
|
||||||
|
// 去除 API 网关前缀,文件访问 URL 不应包含 /prod-api
|
||||||
|
return finalUrl.replace('/prod-api/', '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFeedbackSource() {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
return '小程序'
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
return 'H5'
|
||||||
|
// #endif
|
||||||
|
return 'App'
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyServiceWechat() {
|
||||||
|
uni.setClipboardData({
|
||||||
|
data: serviceWechat,
|
||||||
|
success: () => {
|
||||||
|
uni.showToast({
|
||||||
|
title: '客服微信已复制',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
page {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feedback-container {
|
||||||
|
padding: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 28rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
box-shadow: 0 8rpx 32rpx rgba(102, 126, 234, 0.22);
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro-icon {
|
||||||
|
width: 72rpx;
|
||||||
|
height: 72rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
background: rgba(255, 255, 255, 0.18);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro-title {
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro-desc {
|
||||||
|
color: rgba(255, 255, 255, 0.86);
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-card {
|
||||||
|
background: linear-gradient(135deg, #ffffff 0%, #f8f9fb 100%);
|
||||||
|
border-radius: 24rpx;
|
||||||
|
padding: 8rpx 28rpx 28rpx;
|
||||||
|
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
padding-top: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: block;
|
||||||
|
color: #303133;
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.required::after {
|
||||||
|
content: '*';
|
||||||
|
color: #f56c6c;
|
||||||
|
margin-left: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-text,
|
||||||
|
.count-text {
|
||||||
|
color: #909399;
|
||||||
|
font-size: 22rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.count-text {
|
||||||
|
display: block;
|
||||||
|
text-align: right;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-row,
|
||||||
|
.contact-input,
|
||||||
|
.content-input {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: #f7f8fb;
|
||||||
|
border: 1rpx solid #e8edf3;
|
||||||
|
border-radius: 18rpx;
|
||||||
|
color: #303133;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-row {
|
||||||
|
min-height: 88rpx;
|
||||||
|
padding: 0 22rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-input {
|
||||||
|
height: 88rpx;
|
||||||
|
padding: 0 22rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-input {
|
||||||
|
min-height: 220rpx;
|
||||||
|
padding: 22rpx;
|
||||||
|
line-height: 38rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
color: #c0c4cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-item,
|
||||||
|
.add-image {
|
||||||
|
width: 152rpx;
|
||||||
|
height: 152rpx;
|
||||||
|
border-radius: 18rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-item image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-image {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 42rpx;
|
||||||
|
height: 42rpx;
|
||||||
|
border-bottom-left-radius: 18rpx;
|
||||||
|
background: rgba(0, 0, 0, 0.48);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-image {
|
||||||
|
border: 2rpx dashed #dcdfe6;
|
||||||
|
background: #f7f8fb;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 22rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-section {
|
||||||
|
padding: 32rpx 0 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn,
|
||||||
|
.service-btn {
|
||||||
|
height: 88rpx;
|
||||||
|
border-radius: 44rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
margin: 0 0 20rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
color: #ffffff;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.28);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-btn {
|
||||||
|
color: #667eea;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1rpx solid rgba(102, 126, 234, 0.28);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -40,9 +40,9 @@ const useUserStore = defineStore("user", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
getInfo() {
|
getInfo(silentAuth = false) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
getInfo()
|
getInfo(silentAuth)
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
const user = res.user;
|
const user = res.user;
|
||||||
const avatar =
|
const avatar =
|
||||||
@@ -86,6 +86,16 @@ const useUserStore = defineStore("user", {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// 清理本地登录状态,不调用后端退出接口(用于本地 token 校验失败)
|
||||||
|
resetToken() {
|
||||||
|
this.token = "";
|
||||||
|
this.roles = [];
|
||||||
|
this.permissions = [];
|
||||||
|
this.name = "";
|
||||||
|
this.userId = "";
|
||||||
|
this.avatar = "";
|
||||||
|
removeToken();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
persist: {
|
persist: {
|
||||||
key: 'user-store',
|
key: 'user-store',
|
||||||
|
|||||||
@@ -354,10 +354,12 @@ page {
|
|||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
white-space: nowrap;
|
/* 超长药品名称自动换行,最多 3 行后省略 */
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
word-break: break-all;
|
||||||
flex-shrink: 0;
|
|
||||||
letter-spacing: 0.5rpx;
|
letter-spacing: 0.5rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +461,8 @@ page {
|
|||||||
.info-row {
|
.info-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
/* 关键:使用 flex-start 顶部对齐,避免同行两个 item 超长换行后高度不齐 */
|
||||||
|
align-items: flex-start;
|
||||||
margin: 0 -12rpx;
|
margin: 0 -12rpx;
|
||||||
|
|
||||||
.info-item {
|
.info-item {
|
||||||
@@ -491,12 +495,16 @@ page {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 两列布局下也允许换行(内容起长时撑开多行) */
|
||||||
&:not(.info-item-full) .info-value {
|
&:not(.info-item-full) .info-value {
|
||||||
|
/* 超过 4 行后省略号截断,避免某个超长字段把整个卡片撑得太高 */
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 4;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -512,7 +520,8 @@ page {
|
|||||||
.btn-edit,
|
.btn-edit,
|
||||||
.btn-delete,
|
.btn-delete,
|
||||||
.btn-copy,
|
.btn-copy,
|
||||||
.btn-detail {
|
.btn-detail,
|
||||||
|
.btn-summary {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -552,6 +561,13 @@ page {
|
|||||||
color: $health-info;
|
color: $health-info;
|
||||||
border: 1rpx solid $health-info-border;
|
border: 1rpx solid $health-info-border;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 汇总按钮:与 btn-detail 同一色调(信息色),避免各页面重复定义 */
|
||||||
|
.btn-summary {
|
||||||
|
background: $health-info-bg;
|
||||||
|
color: $health-info;
|
||||||
|
border: 1rpx solid $health-info-border;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
interface BaseRequestConfig {
|
interface BaseRequestConfig {
|
||||||
headers?: {
|
headers?: {
|
||||||
/** 是否在请求头中添加token 默认是 */
|
/** 是否在请求头中添加token 默认是 */
|
||||||
isToken: boolean
|
isToken?: boolean,
|
||||||
|
/** token 失效时是否静默返回错误,不弹重新登录确认框 */
|
||||||
|
silentAuth?: boolean
|
||||||
},
|
},
|
||||||
/** 请求头配置 */
|
/** 请求头配置 */
|
||||||
header?: any,
|
header?: any,
|
||||||
|
|||||||
171
src/utils/imageCompress.ts
Normal file
171
src/utils/imageCompress.ts
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
/**
|
||||||
|
* 跨端图片压缩工具
|
||||||
|
*
|
||||||
|
* 用途:上传附件前压缩图片,避免大图(特别是手机原图 4MB+)导致上传卡死
|
||||||
|
*
|
||||||
|
* - H5:用 Canvas 重绘 + toDataURL('image/jpeg', quality)
|
||||||
|
* - 小程序/APP:用 uni.compressImage API(quality + compressedWidth)
|
||||||
|
*
|
||||||
|
* 策略:
|
||||||
|
* - 原图小于 500KB 不压(避免无谓耗时)
|
||||||
|
* - 最大宽度限制 1280px(横屏照片)或按比例缩放
|
||||||
|
* - JPEG 质量 0.75(体积约 1/5 ~ 1/10,肉眼几乎无差)
|
||||||
|
* - 透明 PNG 也压成 JPEG(牺牲透明通道换取体积),如需透明可改 quality 调用
|
||||||
|
*
|
||||||
|
* 用法:
|
||||||
|
* import { compressImage } from '@/utils/imageCompress'
|
||||||
|
* const compressed = await compressImage(filePath)
|
||||||
|
* uploadFile({ filePath: compressed, ... })
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 不压缩的体积阈值(字节),800KB(小图直接跳过,避免无谓耗时) */
|
||||||
|
const SKIP_COMPRESS_SIZE = 800 * 1024
|
||||||
|
/** 最大边长,超过按比例缩放(保留宽高比)。1920px 兼顾清晰度与体积 */
|
||||||
|
const MAX_SIDE = 1920
|
||||||
|
/** JPEG 压缩质量 0~1。0.85 可保证医疗单据/药品说明书文字清晰 */
|
||||||
|
const JPEG_QUALITY = 0.85
|
||||||
|
|
||||||
|
/**
|
||||||
|
* H5 端压缩:Canvas 重绘 + toBlob
|
||||||
|
*/
|
||||||
|
function compressH5(filePath: string): Promise<string> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image()
|
||||||
|
img.crossOrigin = 'anonymous'
|
||||||
|
img.onload = () => {
|
||||||
|
try {
|
||||||
|
// 计算缩放后的尺寸
|
||||||
|
let { width, height } = img
|
||||||
|
const longSide = Math.max(width, height)
|
||||||
|
if (longSide > MAX_SIDE) {
|
||||||
|
const scale = MAX_SIDE / longSide
|
||||||
|
width = Math.round(width * scale)
|
||||||
|
height = Math.round(height * scale)
|
||||||
|
}
|
||||||
|
// 创建 canvas 重绘
|
||||||
|
const canvas = document.createElement('canvas')
|
||||||
|
canvas.width = width
|
||||||
|
canvas.height = height
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
if (!ctx) {
|
||||||
|
resolve(filePath) // 极端情况降级到原图
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 白底(防止 PNG 透明通道转 JPEG 后变黑)
|
||||||
|
ctx.fillStyle = '#ffffff'
|
||||||
|
ctx.fillRect(0, 0, width, height)
|
||||||
|
ctx.drawImage(img, 0, 0, width, height)
|
||||||
|
// 转成 Blob 返回 ObjectURL(避免 base64 体积膨胀)
|
||||||
|
canvas.toBlob(
|
||||||
|
(blob) => {
|
||||||
|
if (!blob) {
|
||||||
|
resolve(filePath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 释放旧的 ObjectURL(如果是 blob: URL)
|
||||||
|
if (filePath.startsWith('blob:')) {
|
||||||
|
try { URL.revokeObjectURL(filePath) } catch (e) { /* ignore */ }
|
||||||
|
}
|
||||||
|
resolve(URL.createObjectURL(blob))
|
||||||
|
},
|
||||||
|
'image/jpeg',
|
||||||
|
JPEG_QUALITY
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('[imageCompress] H5 压缩失败,降级原图', err)
|
||||||
|
resolve(filePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img.onerror = (err) => {
|
||||||
|
console.warn('[imageCompress] H5 图片加载失败,降级原图', err)
|
||||||
|
resolve(filePath)
|
||||||
|
}
|
||||||
|
img.src = filePath
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小程序/APP 端压缩:uni.compressImage
|
||||||
|
*/
|
||||||
|
function compressMP(filePath: string): Promise<string> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
uni.compressImage({
|
||||||
|
src: filePath,
|
||||||
|
quality: Math.round(JPEG_QUALITY * 100), // 75
|
||||||
|
compressedWidth: MAX_SIDE,
|
||||||
|
success: (res) => resolve(res.tempFilePath),
|
||||||
|
fail: (err) => {
|
||||||
|
console.warn('[imageCompress] uni.compressImage 失败,降级原图', err)
|
||||||
|
resolve(filePath) // 失败降级
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件大小(字节)。
|
||||||
|
* - H5: blob: / data: URL 用 fetch 解析
|
||||||
|
* - 小程序/APP: uni.getFileInfo
|
||||||
|
*/
|
||||||
|
function getFileSize(filePath: string): Promise<number> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// #ifdef H5
|
||||||
|
try {
|
||||||
|
if (filePath.startsWith('blob:') || filePath.startsWith('data:')) {
|
||||||
|
fetch(filePath)
|
||||||
|
.then(r => r.blob())
|
||||||
|
.then(b => resolve(b.size))
|
||||||
|
.catch(() => resolve(0))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} catch (e) { /* fallthrough */ }
|
||||||
|
resolve(0) // 无法获取则不压缩(保守策略)
|
||||||
|
return
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
uni.getFileInfo({
|
||||||
|
filePath,
|
||||||
|
success: (res) => resolve(res.size),
|
||||||
|
fail: () => resolve(0)
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 压缩图片入口(跨端)
|
||||||
|
* @param filePath 图片临时路径
|
||||||
|
* @returns 压缩后的图片路径(如失败则返回原路径)
|
||||||
|
*/
|
||||||
|
export async function compressImage(filePath: string): Promise<string> {
|
||||||
|
if (!filePath) return filePath
|
||||||
|
try {
|
||||||
|
// 检查体积,小图直接跳过
|
||||||
|
const size = await getFileSize(filePath)
|
||||||
|
if (size > 0 && size < SKIP_COMPRESS_SIZE) {
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
// #ifdef H5
|
||||||
|
return await compressH5(filePath)
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
return await compressMP(filePath)
|
||||||
|
// #endif
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('[imageCompress] 压缩过程异常,降级原图', err)
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量压缩图片(串行执行,避免一次性占用过多内存)
|
||||||
|
* @param filePaths 图片路径数组
|
||||||
|
* @returns 压缩后的路径数组(与入参顺序一致)
|
||||||
|
*/
|
||||||
|
export async function compressImages(filePaths: string[]): Promise<string[]> {
|
||||||
|
const result: string[] = []
|
||||||
|
for (const p of filePaths) {
|
||||||
|
result.push(await compressImage(p))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -9,8 +9,10 @@ let timeout = 10000
|
|||||||
const baseUrl = config.baseUrl
|
const baseUrl = config.baseUrl
|
||||||
|
|
||||||
const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
|
const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
|
||||||
|
const metaHeaders = config.headers || {}
|
||||||
// 是否需要设置 token
|
// 是否需要设置 token
|
||||||
const isToken = (config.headers || {}).isToken === false
|
const isToken = metaHeaders.isToken === false
|
||||||
|
const silentAuth = metaHeaders.silentAuth === true
|
||||||
config.header = config.header || {}
|
config.header = config.header || {}
|
||||||
if (getToken() && !isToken) {
|
if (getToken() && !isToken) {
|
||||||
config.header['Authorization'] = 'Bearer ' + getToken()
|
config.header['Authorization'] = 'Bearer ' + getToken()
|
||||||
@@ -42,20 +44,23 @@ const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const msg: string = errorCode[code] || data.msg || errorCode['default']
|
const msg: string = errorCode[code] || data.msg || errorCode['default']
|
||||||
if (code === 401) {
|
if (code === 401) {
|
||||||
showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
|
const authError = { code: 401, msg: '无效的会话,或者会话已过期,请重新登录。' }
|
||||||
if (res.confirm) {
|
if (!silentAuth) {
|
||||||
useUserStore().logOut().then(res => {
|
showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {
|
||||||
uni.reLaunch({ url: '/pages/login' })
|
if (res.confirm) {
|
||||||
})
|
useUserStore().logOut().then(res => {
|
||||||
}
|
uni.reLaunch({ url: '/pages/login' })
|
||||||
})
|
})
|
||||||
reject('无效的会话,或者会话已过期,请重新登录。')
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return reject(silentAuth ? authError : authError.msg)
|
||||||
} else if (code === 500) {
|
} else if (code === 500) {
|
||||||
toast(msg)
|
toast(msg)
|
||||||
reject('500')
|
return reject('500')
|
||||||
} else if (code !== 200) {
|
} else if (code !== 200) {
|
||||||
toast(msg)
|
toast(msg)
|
||||||
reject(code)
|
return reject(code)
|
||||||
}
|
}
|
||||||
resolve(data)
|
resolve(data)
|
||||||
})
|
})
|
||||||
@@ -68,7 +73,9 @@ const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
|
|||||||
} else if (message.includes('Request failed with status code')) {
|
} else if (message.includes('Request failed with status code')) {
|
||||||
message = '系统接口' + message.substr(message.length - 3) + '异常'
|
message = '系统接口' + message.substr(message.length - 3) + '异常'
|
||||||
}
|
}
|
||||||
toast(message)
|
if (!silentAuth) {
|
||||||
|
toast(message)
|
||||||
|
}
|
||||||
reject(error)
|
reject(error)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -31,7 +31,16 @@ const upload = <T>(config: RequestUploadConfig): Promise<ResponseData<T>> => {
|
|||||||
header: config.header,
|
header: config.header,
|
||||||
formData: config.formData,
|
formData: config.formData,
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
let result = JSON.parse(res.data)
|
let result
|
||||||
|
// 后端可能返回 JSON 字符串(正常)或 HTML 错误页(如 413 Payload Too Large)
|
||||||
|
// 必须包 try-catch,否则 JSON.parse 招错后 Promise 永远不 settle,mask loading 永不关闭
|
||||||
|
try {
|
||||||
|
result = JSON.parse(res.data)
|
||||||
|
} catch (e) {
|
||||||
|
toast('上传失败:服务器响应非 JSON 格式(可能文件过大)')
|
||||||
|
reject('上传失败:响应解析失败')
|
||||||
|
return
|
||||||
|
}
|
||||||
const code = result.code || 200
|
const code = result.code || 200
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const msg = errorCode[code] || result.msg || errorCode['default']
|
const msg = errorCode[code] || result.msg || errorCode['default']
|
||||||
|
|||||||
Reference in New Issue
Block a user