合并代码
This commit is contained in:
parent
438d101c0c
commit
7031bdcdb3
|
|
@ -0,0 +1,530 @@
|
|||
<template>
|
||||
<view v-if="visible" class="overlay" @touchmove.prevent.self>
|
||||
<view class="box" :style="boxStyle" @touchstart.stop.prevent="onDragStartTouch"
|
||||
@mousedown.stop.prevent="onDragStartMouse">
|
||||
<view class="header" ref="headerRef">
|
||||
<view class="title">{{ title }}</view>
|
||||
<view class="actions">
|
||||
<button class="btn" @click="cancel">取消</button>
|
||||
<button class="btn" @click="confirm">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<picker-view class="picker-view" :style="{
|
||||
height: pickerHeight + 'px',
|
||||
'--item-h': ITEM_H + 'px',
|
||||
'--cols': displayColumns.length || 1
|
||||
}" :value="normalizedSelectedIndexes" @change="onPickerChange">
|
||||
<picker-view-column class="picker-view-column" v-for="(col, ci) in displayColumns" :key="ci">
|
||||
<view v-for="(item, i) in col" :key="i" class="picker-item">{{ item }}</view>
|
||||
<!-- :style="{ height: ITEM_H + 'px', lineHeight: ITEM_H + 'px' }" -->
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
|
||||
<view class="resize-handle" @touchstart.stop.prevent="onResizeStartTouch"
|
||||
@mousedown.stop.prevent="onResizeStartMouse">
|
||||
<view class="grip"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
computed,
|
||||
watch,
|
||||
onMounted,
|
||||
onBeforeUnmount,
|
||||
nextTick
|
||||
} from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '请选择'
|
||||
},
|
||||
initLeft: {
|
||||
type: Number,
|
||||
default: 50
|
||||
},
|
||||
initTop: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
initWidth: {
|
||||
type: Number,
|
||||
default: 320
|
||||
},
|
||||
initHeight: {
|
||||
type: Number,
|
||||
default: 320
|
||||
},
|
||||
minWidth: {
|
||||
type: Number,
|
||||
default: 180
|
||||
},
|
||||
minHeight: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
maxWidth: {
|
||||
type: Number,
|
||||
default: 1000
|
||||
},
|
||||
maxHeight: {
|
||||
type: Number,
|
||||
default: 1200
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => [
|
||||
[]
|
||||
]
|
||||
},
|
||||
nameKey: {
|
||||
type: [String, Array],
|
||||
default: 'name'
|
||||
},
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
const emit = defineEmits(['update:modelValue', 'confirm', 'change', 'update:position', 'update:size']);
|
||||
|
||||
/* ========== 基本可见性 / 同步 ========== */
|
||||
const visible = ref(props.modelValue);
|
||||
watch(() => props.modelValue, v => visible.value = v);
|
||||
watch(visible, v => emit('update:modelValue', v));
|
||||
|
||||
/* ========== 位置 / 尺寸 ========== */
|
||||
const left = ref(props.initLeft);
|
||||
const top = ref(props.initTop);
|
||||
const width = ref(props.initWidth);
|
||||
const height = ref(props.initHeight);
|
||||
|
||||
/* ========== 固定行高(关键:整数像素) ========== */
|
||||
const ITEM_H = 44; // 行高(px),保持整数像素
|
||||
const HEADER_H = 44; // header 高度(px),与你样式一致
|
||||
|
||||
/* ========== selectedIndexes 初始值 & 正规化 ========== */
|
||||
const selectedIndexes = ref(
|
||||
(props.value && props.value.length) ? props.value.map(v => Number(v || 0)) : (Array.isArray(props.columns) ?
|
||||
props.columns.map(() => 0) : [])
|
||||
);
|
||||
watch(() => props.value, v => {
|
||||
if (v && v.length) {
|
||||
selectedIndexes.value = v.map(x => Number(x || 0));
|
||||
clampSelectedIndexes();
|
||||
}
|
||||
});
|
||||
const normalizedSelectedIndexes = computed(() => selectedIndexes.value.map(v => Number(v || 0)));
|
||||
|
||||
/* ========== columns -> displayColumns(显示文本) ========== */
|
||||
function getByPath(obj, path) {
|
||||
if (obj == null) return undefined;
|
||||
if (!path) return obj;
|
||||
const parts = path.split('.');
|
||||
let cur = obj;
|
||||
for (let p of parts) {
|
||||
if (cur == null) return undefined;
|
||||
cur = cur[p];
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
const displayColumns = computed(() => {
|
||||
const raw = props.columns || [];
|
||||
const nk = props.nameKey;
|
||||
return raw.map((col, ci) => {
|
||||
if (!Array.isArray(col)) return [];
|
||||
return col.map(item => {
|
||||
if (item == null) return '';
|
||||
if (typeof item === 'object') {
|
||||
let keyToUse = Array.isArray(nk) ? (nk[ci] !== undefined ? nk[ci] : nk[0]) :
|
||||
nk;
|
||||
if (!keyToUse) {
|
||||
return item.name ?? item.label ?? item.title ?? String(item);
|
||||
}
|
||||
const val = getByPath(item, keyToUse);
|
||||
return (val === undefined || val === null) ? (item.name ?? item.label ?? item
|
||||
.title ?? String(item)) : String(val);
|
||||
} else {
|
||||
return String(item);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
const rawColumns = computed(() => (props.columns || []).map(col => Array.isArray(col) ? col : []));
|
||||
|
||||
/* ========== 屏幕信息(只用 uni.getSystemInfoSync,App/H5/小程序 均可用) ========== */
|
||||
let screenW = 800,
|
||||
screenH = 600; // 安全默认值(不会访问 window)
|
||||
onMounted(() => {
|
||||
try {
|
||||
const info = uni.getSystemInfoSync();
|
||||
// uni.getSystemInfoSync 在 App/H5/小程序 都可用,优先使用
|
||||
screenW = info.windowWidth || info.screenWidth || screenW;
|
||||
screenH = info.windowHeight || info.screenHeight || screenH;
|
||||
} catch (e) {
|
||||
// 若异常,不尝试访问 window,保留默认值
|
||||
screenW = screenW;
|
||||
screenH = screenH;
|
||||
}
|
||||
});
|
||||
|
||||
/* ========== 拖拽 / 缩放(保持原逻辑) ========== */
|
||||
let dragging = false;
|
||||
let dragStart = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
left: 0,
|
||||
top: 0
|
||||
};
|
||||
let resizing = false;
|
||||
let resizeStart = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0,
|
||||
h: 0
|
||||
};
|
||||
|
||||
function onDragStartTouch(e) {
|
||||
const t = e.touches && e.touches[0];
|
||||
if (t) startDrag(t.clientX, t.clientY);
|
||||
}
|
||||
|
||||
function onDragStartMouse(e) {
|
||||
startDrag(e.clientX, e.clientY);
|
||||
}
|
||||
|
||||
function startDrag(cx, cy) {
|
||||
dragging = true;
|
||||
dragStart.x = cx;
|
||||
dragStart.y = cy;
|
||||
dragStart.left = left.value;
|
||||
dragStart.top = top.value;
|
||||
}
|
||||
|
||||
function onResizeStartTouch(e) {
|
||||
const t = e.touches && e.touches[0];
|
||||
if (t) startResize(t.clientX, t.clientY);
|
||||
}
|
||||
|
||||
function onResizeStartMouse(e) {
|
||||
startResize(e.clientX, e.clientY);
|
||||
}
|
||||
|
||||
function startResize(cx, cy) {
|
||||
resizing = true;
|
||||
resizeStart.x = cx;
|
||||
resizeStart.y = cy;
|
||||
resizeStart.w = width.value;
|
||||
resizeStart.h = height.value;
|
||||
}
|
||||
|
||||
function onTouchMove(e) {
|
||||
if (!dragging && !resizing) return;
|
||||
const t = e.touches && e.touches[0];
|
||||
if (t) handleMove(t.clientX, t.clientY, e);
|
||||
}
|
||||
|
||||
function onMouseMove(e) {
|
||||
if (!dragging && !resizing) return;
|
||||
handleMove(e.clientX, e.clientY, e);
|
||||
}
|
||||
|
||||
function handleMove(cx, cy, e) {
|
||||
if (dragging) {
|
||||
const dx = cx - dragStart.x;
|
||||
const dy = cy - dragStart.y;
|
||||
left.value = Math.min(Math.max(0, dragStart.left + dx), Math.max(0, screenW - width.value));
|
||||
top.value = Math.min(Math.max(0, dragStart.top + dy), Math.max(0, screenH - height.value));
|
||||
emit('update:position', {
|
||||
left: left.value,
|
||||
top: top.value
|
||||
});
|
||||
} else if (resizing) {
|
||||
const dx = cx - resizeStart.x;
|
||||
const dy = cy - resizeStart.y;
|
||||
let nw = Math.min(props.maxWidth, Math.max(props.minWidth, Math.round(resizeStart.w + dx)));
|
||||
let nh = Math.min(props.maxHeight, Math.max(props.minHeight, Math.round(resizeStart.h + dy)));
|
||||
if (left.value + nw > screenW) nw = screenW - left.value;
|
||||
if (top.value + nh > screenH) nh = screenH - top.value;
|
||||
width.value = nw;
|
||||
height.value = nh;
|
||||
emit('update:size', {
|
||||
width: width.value,
|
||||
height: height.value
|
||||
});
|
||||
}
|
||||
if (e && e.preventDefault) e.preventDefault();
|
||||
}
|
||||
|
||||
function onMouseUp() {
|
||||
if (dragging) dragging = false;
|
||||
if (resizing) resizing = false;
|
||||
}
|
||||
|
||||
function onTouchEnd() {
|
||||
if (dragging) dragging = false;
|
||||
if (resizing) resizing = false;
|
||||
}
|
||||
|
||||
/* ========== picker 行数 / 高度 计算(关键) ========== */
|
||||
const pickerHeight = computed(() => {
|
||||
const avail = Math.max(0, Math.round(height.value) - HEADER_H);
|
||||
let rows = Math.floor(avail / ITEM_H);
|
||||
if (rows < 1) rows = 1;
|
||||
if (rows % 2 === 0) rows = rows - 1 > 0 ? rows - 1 : 1;
|
||||
return rows * ITEM_H;
|
||||
});
|
||||
|
||||
/* ========== clamp helper ========== */
|
||||
function clampSelectedIndexes() {
|
||||
const colsArr = rawColumns.value || [];
|
||||
if (selectedIndexes.value.length !== colsArr.length) {
|
||||
selectedIndexes.value = Array.from({
|
||||
length: colsArr.length
|
||||
}, (_, i) => selectedIndexes.value[i] ?? 0);
|
||||
}
|
||||
selectedIndexes.value = selectedIndexes.value.map((idx, ci) => {
|
||||
const col = Array.isArray(colsArr[ci]) ? colsArr[ci] : [];
|
||||
const maxIdx = Math.max(0, col.length - 1);
|
||||
return col.length ? Math.min(Math.max(0, Number(idx) || 0), maxIdx) : 0;
|
||||
});
|
||||
}
|
||||
|
||||
/* ========== 对齐重置逻辑(核心) ========== */
|
||||
let resetTimer = null;
|
||||
|
||||
function resetPickerAlign(delay = 40) {
|
||||
if (resetTimer) clearTimeout(resetTimer);
|
||||
resetTimer = setTimeout(() => {
|
||||
nextTick(() => {
|
||||
clampSelectedIndexes();
|
||||
selectedIndexes.value = selectedIndexes.value.map(v => Number(v || 0));
|
||||
});
|
||||
resetTimer = null;
|
||||
}, delay);
|
||||
}
|
||||
|
||||
/* 在关键变化上调用重置:columns / visible / pickerHeight */
|
||||
watch(() => props.columns, () => {
|
||||
clampSelectedIndexes();
|
||||
resetPickerAlign(30);
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
});
|
||||
|
||||
watch(() => visible.value, (v) => {
|
||||
if (v) {
|
||||
resetPickerAlign(60);
|
||||
setTimeout(() => resetPickerAlign(40), 120);
|
||||
}
|
||||
});
|
||||
|
||||
watch(() => pickerHeight.value, () => {
|
||||
resetPickerAlign(30);
|
||||
});
|
||||
|
||||
/* ========== picker change / confirm / cancel ========== */
|
||||
function onPickerChange(e) {
|
||||
const val = (e && e.detail && e.detail.value) ? e.detail.value : e;
|
||||
if (Array.isArray(val)) {
|
||||
selectedIndexes.value = val.map((v, ci) => {
|
||||
const col = rawColumns.value[ci] || [];
|
||||
const max = Math.max(0, col.length - 1);
|
||||
const num = Number(v) || 0;
|
||||
return col.length ? Math.min(Math.max(0, num), max) : 0;
|
||||
});
|
||||
}
|
||||
emit('change', selectedIndexes.value.slice());
|
||||
resetPickerAlign(80);
|
||||
}
|
||||
|
||||
function confirm() {
|
||||
const result = selectedIndexes.value.map((idx, ci) => {
|
||||
const col = rawColumns.value[ci] || [];
|
||||
const display = (displayColumns.value[ci] && displayColumns.value[ci][idx] !== undefined) ?
|
||||
displayColumns.value[ci][idx] : (col[idx] !== undefined ? String(col[idx]) : '');
|
||||
const val = col[idx] !== undefined ? col[idx] : (display || null);
|
||||
return {
|
||||
index: idx,
|
||||
value: val,
|
||||
display
|
||||
};
|
||||
});
|
||||
emit('confirm', result);
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
/* ========== boxStyle ========== */
|
||||
const boxStyle = computed(() => ({
|
||||
position: 'fixed',
|
||||
left: `${Math.round(left.value)}px`,
|
||||
top: `${Math.round(top.value)}px`,
|
||||
width: `${Math.round(width.value)}px`,
|
||||
height: `${Math.round(height.value)}px`,
|
||||
zIndex: 1000,
|
||||
background: '#fff',
|
||||
borderRadius: '8px',
|
||||
boxShadow: '0 8px 24px rgba(0,0,0,0.12)',
|
||||
overflow: 'hidden',
|
||||
transform: 'translateZ(0)'
|
||||
}));
|
||||
|
||||
/* ========== 全局事件监听(更稳健的平台检测) ========== */
|
||||
/* 我们优先使用 window/document(H5 环境),如果都不可用(如原生 App),则不添加全局监听,
|
||||
因为原生 App 的触摸事件通常在组件内部就能处理(touchstart/touchmove/touchend) */
|
||||
let globalEventTarget = null;
|
||||
if (typeof window !== 'undefined' && window && typeof window.addEventListener === 'function') {
|
||||
globalEventTarget = window;
|
||||
} else if (typeof document !== 'undefined' && document && typeof document.addEventListener === 'function') {
|
||||
globalEventTarget = document;
|
||||
} else {
|
||||
globalEventTarget = null; // 在原生 App(非 H5)中通常为 null
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (globalEventTarget) {
|
||||
try {
|
||||
globalEventTarget.addEventListener('mousemove', onMouseMove);
|
||||
globalEventTarget.addEventListener('mouseup', onMouseUp);
|
||||
// touchmove 需要 passive:false 以阻止默认行为
|
||||
globalEventTarget.addEventListener('touchmove', onTouchMove, {
|
||||
passive: false
|
||||
});
|
||||
globalEventTarget.addEventListener('touchend', onTouchEnd);
|
||||
} catch (e) {
|
||||
// 如果某些环境不支持 options 参数,用 fallback
|
||||
try {
|
||||
globalEventTarget.addEventListener('touchmove', onTouchMove);
|
||||
globalEventTarget.addEventListener('touchend', onTouchEnd);
|
||||
} catch (err) {
|
||||
// 忽略
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (globalEventTarget) {
|
||||
try {
|
||||
globalEventTarget.removeEventListener('mousemove', onMouseMove);
|
||||
globalEventTarget.removeEventListener('mouseup', onMouseUp);
|
||||
globalEventTarget.removeEventListener('touchmove', onTouchMove);
|
||||
globalEventTarget.removeEventListener('touchend', onTouchEnd);
|
||||
} catch (e) {
|
||||
// 忽略
|
||||
}
|
||||
}
|
||||
if (resetTimer) {
|
||||
clearTimeout(resetTimer);
|
||||
resetTimer = null;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 900;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.box {
|
||||
background: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 8px;
|
||||
border-bottom: 1px solid #eee;
|
||||
background: linear-gradient(90deg, #fff, #fafafa);
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 6px 8px;
|
||||
border-radius: 6px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.picker-view {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.picker-view-column {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: calc(100% / var(--cols, 1));
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.picker-item {
|
||||
display: block;
|
||||
/* height: var(--item-h);
|
||||
line-height: var(--item-h); */
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.resize-handle {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
bottom: 6px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
.grip {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
border: 1px dashed #bbb;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
<template>
|
||||
<view class="contain">
|
||||
<view v-show="moreindex!=-1 || topbuttontarget!=-1 || openjianhuo || opengaijia || opendata || opencgr " class="mengban"
|
||||
@click="moreindex=-1; topbuttontarget=-1;openjianhuo=false;opengaijia=false;opendata=false;opencgr=false"></view>
|
||||
<view v-show="moreindex!=-1 || topbuttontarget!=-1 || openjianhuo || opengaijia || opendata || opencgr "
|
||||
class="mengban"
|
||||
@click="moreindex=-1; topbuttontarget=-1;openjianhuo=false;opengaijia=false;opendata=false;opencgr=false">
|
||||
</view>
|
||||
<!-- 日期 -->
|
||||
<view class="calendar-father" v-show="opendata">
|
||||
<calendar @datachange="dateget" />
|
||||
|
|
@ -1025,8 +1027,10 @@
|
|||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<u-select v-model="opencgr" :list="cgrlist" label-name="cgBy" value-name="cgBy" ></u-select>
|
||||
<u-select v-model="opengys" :list="gyslist" label-name="suppliersName" value-name="suppliers" ></u-select>
|
||||
<!-- <u-select v-model="opencgr" :list="cgrlist" label-name="cgBy" value-name="cgBy" ></u-select> -->
|
||||
<!-- <u-select v-model="opengys" :list="gyslist" label-name="suppliersName" value-name="suppliers" ></u-select> -->
|
||||
<superpicker v-model:modelValue="opengys" :columns="[gyslist]" nameKey="suppliersName" :init-left="80" :init-top="120" :init-width="360"
|
||||
:init-height="360" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
|
@ -1035,6 +1039,7 @@
|
|||
import { queryInvoicingList, getCgdMaterialTreeData, queryNuInfoByNuId, updateKfstatus, queryCgdList, queryCgdInfoList, queryWlInfoByWlId, voidedCgdMain, getCgrLis, getGysList } from './api/lunpan.js'
|
||||
import { onShow, onLoad, onHide, onPageScroll } from "@dcloudio/uni-app"
|
||||
import calendar from '@/component/public/calendar.vue'
|
||||
import superpicker from '@/component/public/superpicker.vue'
|
||||
|
||||
const typechange = ref(0);
|
||||
const serverUrl = ref("");
|
||||
|
|
@ -1074,6 +1079,7 @@
|
|||
})
|
||||
getGysList().then((res : any) => {
|
||||
gyslist.value = res.result;
|
||||
console.log("isright",res)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -574,7 +574,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|||
)
|
||||
]);
|
||||
}
|
||||
const camera = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["styles", [_style_0]], ["__file", "D:/项目/hldy_app_mini/pages/camera.nvue"]]);
|
||||
const camera = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["styles", [_style_0]], ["__file", "D:/hldy_app_mini/pages/camera.nvue"]]);
|
||||
export {
|
||||
camera as default
|
||||
};
|
||||
|
|
|
|||
|
|
@ -577,7 +577,7 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|||
)
|
||||
]);
|
||||
}
|
||||
const fullcamera = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["styles", [_style_0]], ["__file", "D:/项目/hldy_app_mini/pages/fullcamera.nvue"]]);
|
||||
const fullcamera = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["styles", [_style_0]], ["__file", "D:/hldy_app_mini/pages/fullcamera.nvue"]]);
|
||||
export {
|
||||
fullcamera as default
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue