commit
This commit is contained in:
@@ -170,3 +170,128 @@ body {
|
||||
margin-top: 10px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
|
||||
/*************************覆盖vant默认CSS********************************/
|
||||
.van-dropdown-menu__bar{
|
||||
box-shadow: unset;
|
||||
}
|
||||
|
||||
|
||||
/*****************************申请表单CSS********************************/
|
||||
.form-container {
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
.form-container .form-group {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.form-container .form-actions {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 12px 16px;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.form-container .form-actions .van-button {
|
||||
flex: 1;
|
||||
margin: 0 8px;
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.form-container .van-cell-group {
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-container .van-cell-group__title {
|
||||
font-size: 15px;
|
||||
color: var(--color-black);
|
||||
font-weight: 600;
|
||||
padding: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-container .van-cell-group__title::before{
|
||||
content: "";
|
||||
width: 5px;
|
||||
background: var(--color-primary);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.form-container .van-field__label {
|
||||
width: 90px;
|
||||
color: #323233;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.form-container .van-field__value {
|
||||
color: #323233;
|
||||
}
|
||||
|
||||
.form-container .van-cell {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.form-container .van-cell:not(:last-child)::after {
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
.form-container .direction-column-field .van-field__label {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.form-container .direction-column-field .van-field__body {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-container .direction-column-field .van-field__control {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/***************************查看详情CSS********************************/
|
||||
.detail-container {
|
||||
background: #f9f9f9
|
||||
}
|
||||
|
||||
.detail-container .van-cell-group__title{
|
||||
font-size: 15px;
|
||||
color: var(--color-black);
|
||||
font-weight: 600;
|
||||
padding: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.detail-container .van-cell-group__title::before{
|
||||
content: "";
|
||||
width: 5px;
|
||||
background: var(--color-primary);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.detail-container .direction-column-cell{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.detail-container .direction-column-cell .van-cell__value{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-13205
File diff suppressed because one or more lines are too long
+13205
File diff suppressed because it is too large
Load Diff
+112
@@ -0,0 +1,112 @@
|
||||
@charset "UTF-8";
|
||||
/* 数据量大与遮罩交互冲突优化 */
|
||||
.v-modal.v-modal-leave {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 6px;
|
||||
border: 2px solid transparent;
|
||||
background-color: var(--scrollbar-background-color);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.el-dialog__header {
|
||||
padding: 15px 20px 15px 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--border-color-lighter);
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
flex: 1;
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
font-weight: 600;
|
||||
line-height: 1.5;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.el-dialog__headerbtn{
|
||||
top: auto;
|
||||
right: auto;
|
||||
line-height: 1;
|
||||
font-size: 18px;
|
||||
position: static;
|
||||
}
|
||||
|
||||
.el-dialog__footer {
|
||||
padding-bottom: 12px;
|
||||
border-top: 1px solid var(--border-color-lighter);
|
||||
}
|
||||
|
||||
.el-table thead {
|
||||
color: var(--color-text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.el-table td.el-table__cell div {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
|
||||
.el-card {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-card + .el-card {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.el-message:not(.ele-message-border){
|
||||
background: var(--popover-background-color);
|
||||
-webkit-box-shadow: var(--box-shadow-light);
|
||||
box-shadow: var(--box-shadow-light);
|
||||
border-radius: 2px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.el-message {
|
||||
min-width: auto;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.el-message .el-message__icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.el-message .el-icon-success {
|
||||
color: var(--color-success);
|
||||
}
|
||||
|
||||
.el-message:not(.ele-message-border) .el-message__content {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.el-message .el-message__content {
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.el-button{
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.el-descriptions .is-bordered{
|
||||
table-layout: fixed;!important;
|
||||
}
|
||||
|
||||
+1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,927 @@
|
||||
/*
|
||||
|
||||
PinchZoom.js
|
||||
Copyright (c) Manuel Stofer 2013 - today
|
||||
|
||||
Author: Manuel Stofer (mst@rtp.ch)
|
||||
Version: 2.3.5
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// polyfills
|
||||
if (typeof Object.assign != 'function') {
|
||||
// Must be writable: true, enumerable: false, configurable: true
|
||||
Object.defineProperty(Object, "assign", {
|
||||
value: function assign(target, varArgs) { // .length of function is 2
|
||||
if (target == null) { // TypeError if undefined or null
|
||||
throw new TypeError('Cannot convert undefined or null to object');
|
||||
}
|
||||
|
||||
var to = Object(target);
|
||||
|
||||
for (var index = 1; index < arguments.length; index++) {
|
||||
var nextSource = arguments[index];
|
||||
|
||||
if (nextSource != null) { // Skip over if undefined or null
|
||||
for (var nextKey in nextSource) {
|
||||
// Avoid bugs when hasOwnProperty is shadowed
|
||||
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
|
||||
to[nextKey] = nextSource[nextKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return to;
|
||||
},
|
||||
writable: true,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof Array.from != 'function') {
|
||||
Array.from = function (object) {
|
||||
return [].slice.call(object);
|
||||
};
|
||||
}
|
||||
|
||||
// utils
|
||||
var buildElement = function(str) {
|
||||
// empty string as title argument required by IE and Edge
|
||||
var tmp = document.implementation.createHTMLDocument('');
|
||||
tmp.body.innerHTML = str;
|
||||
return Array.from(tmp.body.children)[0];
|
||||
};
|
||||
|
||||
var triggerEvent = function(el, name) {
|
||||
var event = document.createEvent('HTMLEvents');
|
||||
event.initEvent(name, true, false);
|
||||
el.dispatchEvent(event);
|
||||
};
|
||||
|
||||
var definePinchZoom = function () {
|
||||
|
||||
/**
|
||||
* Pinch zoom
|
||||
* @param el
|
||||
* @param options
|
||||
* @constructor
|
||||
*/
|
||||
var PinchZoom = function (el, options) {
|
||||
this.el = el;
|
||||
this.zoomFactor = 1;
|
||||
this.lastScale = 1;
|
||||
this.offset = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
this.initialOffset = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
};
|
||||
this.options = Object.assign({}, this.defaults, options);
|
||||
this.setupMarkup();
|
||||
this.bindEvents();
|
||||
this.update();
|
||||
|
||||
// The image may already be loaded when PinchZoom is initialized,
|
||||
// and then the load event (which trigger update) will never fire.
|
||||
if (this.isImageLoaded(this.el)) {
|
||||
this.updateAspectRatio();
|
||||
this.setupOffsets();
|
||||
}
|
||||
|
||||
this.enable();
|
||||
|
||||
},
|
||||
sum = function (a, b) {
|
||||
return a + b;
|
||||
},
|
||||
isCloseTo = function (value, expected) {
|
||||
return value > expected - 0.01 && value < expected + 0.01;
|
||||
};
|
||||
|
||||
PinchZoom.prototype = {
|
||||
|
||||
defaults: {
|
||||
tapZoomFactor: 2,
|
||||
zoomOutFactor: 1.3,
|
||||
animationDuration: 300,
|
||||
maxZoom: 4,
|
||||
minZoom: 0.5,
|
||||
draggableUnzoomed: true,
|
||||
lockDragAxis: false,
|
||||
setOffsetsOnce: false,
|
||||
use2d: true,
|
||||
zoomStartEventName: 'pz_zoomstart',
|
||||
zoomUpdateEventName: 'pz_zoomupdate',
|
||||
zoomEndEventName: 'pz_zoomend',
|
||||
dragStartEventName: 'pz_dragstart',
|
||||
dragUpdateEventName: 'pz_dragupdate',
|
||||
dragEndEventName: 'pz_dragend',
|
||||
doubleTapEventName: 'pz_doubletap',
|
||||
verticalPadding: 0,
|
||||
horizontalPadding: 0,
|
||||
onZoomStart: null,
|
||||
onZoomEnd: null,
|
||||
onZoomUpdate: null,
|
||||
onDragStart: null,
|
||||
onDragEnd: null,
|
||||
onDragUpdate: null,
|
||||
onDoubleTap: null
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for 'dragstart'
|
||||
* @param event
|
||||
*/
|
||||
handleDragStart: function (event) {
|
||||
triggerEvent(this.el, this.options.dragStartEventName);
|
||||
if(typeof this.options.onDragStart == "function"){
|
||||
this.options.onDragStart(this, event)
|
||||
}
|
||||
this.stopAnimation();
|
||||
this.lastDragPosition = false;
|
||||
this.hasInteraction = true;
|
||||
this.handleDrag(event);
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for 'drag'
|
||||
* @param event
|
||||
*/
|
||||
handleDrag: function (event) {
|
||||
var touch = this.getTouches(event)[0];
|
||||
this.drag(touch, this.lastDragPosition);
|
||||
this.offset = this.sanitizeOffset(this.offset);
|
||||
this.lastDragPosition = touch;
|
||||
},
|
||||
|
||||
handleDragEnd: function () {
|
||||
triggerEvent(this.el, this.options.dragEndEventName);
|
||||
if(typeof this.options.onDragEnd == "function"){
|
||||
this.options.onDragEnd(this, event)
|
||||
}
|
||||
this.end();
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for 'zoomstart'
|
||||
* @param event
|
||||
*/
|
||||
handleZoomStart: function (event) {
|
||||
triggerEvent(this.el, this.options.zoomStartEventName);
|
||||
if(typeof this.options.onZoomStart == "function"){
|
||||
this.options.onZoomStart(this, event)
|
||||
}
|
||||
this.stopAnimation();
|
||||
this.lastScale = 1;
|
||||
this.nthZoom = 0;
|
||||
this.lastZoomCenter = false;
|
||||
this.hasInteraction = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for 'zoom'
|
||||
* @param event
|
||||
*/
|
||||
handleZoom: function (event, newScale) {
|
||||
// a relative scale factor is used
|
||||
var touchCenter = this.getTouchCenter(this.getTouches(event)),
|
||||
scale = newScale / this.lastScale;
|
||||
this.lastScale = newScale;
|
||||
|
||||
// the first touch events are thrown away since they are not precise
|
||||
this.nthZoom += 1;
|
||||
if (this.nthZoom > 3) {
|
||||
|
||||
this.scale(scale, touchCenter);
|
||||
this.drag(touchCenter, this.lastZoomCenter);
|
||||
}
|
||||
this.lastZoomCenter = touchCenter;
|
||||
},
|
||||
|
||||
handleZoomEnd: function () {
|
||||
triggerEvent(this.el, this.options.zoomEndEventName);
|
||||
if(typeof this.options.onZoomEnd == "function"){
|
||||
this.options.onZoomEnd(this, event)
|
||||
}
|
||||
this.end();
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for 'doubletap'
|
||||
* @param event
|
||||
*/
|
||||
handleDoubleTap: function (event) {
|
||||
var center = this.getTouches(event)[0],
|
||||
zoomFactor = this.zoomFactor > 1 ? 1 : this.options.tapZoomFactor,
|
||||
startZoomFactor = this.zoomFactor,
|
||||
updateProgress = (function (progress) {
|
||||
this.scaleTo(startZoomFactor + progress * (zoomFactor - startZoomFactor), center);
|
||||
}).bind(this);
|
||||
|
||||
if (this.hasInteraction) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isDoubleTap = true;
|
||||
|
||||
if (startZoomFactor > zoomFactor) {
|
||||
center = this.getCurrentZoomCenter();
|
||||
}
|
||||
|
||||
this.animate(this.options.animationDuration, updateProgress, this.swing);
|
||||
triggerEvent(this.el, this.options.doubleTapEventName);
|
||||
if(typeof this.options.onDoubleTap == "function"){
|
||||
this.options.onDoubleTap(this, event)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Compute the initial offset
|
||||
*
|
||||
* the element should be centered in the container upon initialization
|
||||
*/
|
||||
computeInitialOffset: function () {
|
||||
this.initialOffset = {
|
||||
x: -Math.abs(this.el.offsetWidth * this.getInitialZoomFactor() - this.container.offsetWidth) / 2,
|
||||
y: -Math.abs(this.el.offsetHeight * this.getInitialZoomFactor() - this.container.offsetHeight) / 2,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset current image offset to that of the initial offset
|
||||
*/
|
||||
resetOffset: function() {
|
||||
this.offset.x = this.initialOffset.x;
|
||||
this.offset.y = this.initialOffset.y;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine if image is loaded
|
||||
*/
|
||||
isImageLoaded: function (el) {
|
||||
if (el.nodeName === 'IMG') {
|
||||
return el.complete && el.naturalHeight !== 0;
|
||||
} else {
|
||||
return Array.from(el.querySelectorAll('img')).every(this.isImageLoaded);
|
||||
}
|
||||
},
|
||||
|
||||
setupOffsets: function() {
|
||||
if (this.options.setOffsetsOnce && this._isOffsetsSet) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isOffsetsSet = true;
|
||||
|
||||
this.computeInitialOffset();
|
||||
this.resetOffset();
|
||||
},
|
||||
|
||||
/**
|
||||
* Max / min values for the offset
|
||||
* @param offset
|
||||
* @return {Object} the sanitized offset
|
||||
*/
|
||||
sanitizeOffset: function (offset) {
|
||||
var elWidth = this.el.offsetWidth * this.getInitialZoomFactor() * this.zoomFactor;
|
||||
var elHeight = this.el.offsetHeight * this.getInitialZoomFactor() * this.zoomFactor;
|
||||
var maxX = elWidth - this.getContainerX() + this.options.horizontalPadding,
|
||||
maxY = elHeight - this.getContainerY() + this.options.verticalPadding,
|
||||
maxOffsetX = Math.max(maxX, 0),
|
||||
maxOffsetY = Math.max(maxY, 0),
|
||||
minOffsetX = Math.min(maxX, 0) - this.options.horizontalPadding,
|
||||
minOffsetY = Math.min(maxY, 0) - this.options.verticalPadding;
|
||||
|
||||
return {
|
||||
x: Math.min(Math.max(offset.x, minOffsetX), maxOffsetX),
|
||||
y: Math.min(Math.max(offset.y, minOffsetY), maxOffsetY)
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Scale to a specific zoom factor (not relative)
|
||||
* @param zoomFactor
|
||||
* @param center
|
||||
*/
|
||||
scaleTo: function (zoomFactor, center) {
|
||||
this.scale(zoomFactor / this.zoomFactor, center);
|
||||
},
|
||||
|
||||
/**
|
||||
* Scales the element from specified center
|
||||
* @param scale
|
||||
* @param center
|
||||
*/
|
||||
scale: function (scale, center) {
|
||||
scale = this.scaleZoomFactor(scale);
|
||||
this.addOffset({
|
||||
x: (scale - 1) * (center.x + this.offset.x),
|
||||
y: (scale - 1) * (center.y + this.offset.y)
|
||||
});
|
||||
triggerEvent(this.el, this.options.zoomUpdateEventName);
|
||||
if(typeof this.options.onZoomUpdate == "function"){
|
||||
this.options.onZoomUpdate(this, event)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Scales the zoom factor relative to current state
|
||||
* @param scale
|
||||
* @return the actual scale (can differ because of max min zoom factor)
|
||||
*/
|
||||
scaleZoomFactor: function (scale) {
|
||||
var originalZoomFactor = this.zoomFactor;
|
||||
this.zoomFactor *= scale;
|
||||
this.zoomFactor = Math.min(this.options.maxZoom, Math.max(this.zoomFactor, this.options.minZoom));
|
||||
return this.zoomFactor / originalZoomFactor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determine if the image is in a draggable state
|
||||
*
|
||||
* When the image can be dragged, the drag event is acted upon and cancelled.
|
||||
* When not draggable, the drag event bubbles through this component.
|
||||
*
|
||||
* @return {Boolean}
|
||||
*/
|
||||
canDrag: function () {
|
||||
return this.options.draggableUnzoomed || !isCloseTo(this.zoomFactor, 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* Drags the element
|
||||
* @param center
|
||||
* @param lastCenter
|
||||
*/
|
||||
drag: function (center, lastCenter) {
|
||||
if (lastCenter) {
|
||||
if(this.options.lockDragAxis) {
|
||||
// lock scroll to position that was changed the most
|
||||
if(Math.abs(center.x - lastCenter.x) > Math.abs(center.y - lastCenter.y)) {
|
||||
this.addOffset({
|
||||
x: -(center.x - lastCenter.x),
|
||||
y: 0
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.addOffset({
|
||||
y: -(center.y - lastCenter.y),
|
||||
x: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.addOffset({
|
||||
y: -(center.y - lastCenter.y),
|
||||
x: -(center.x - lastCenter.x)
|
||||
});
|
||||
}
|
||||
triggerEvent(this.el, this.options.dragUpdateEventName);
|
||||
if(typeof this.options.onDragUpdate == "function"){
|
||||
this.options.onDragUpdate(this, event)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the touch center of multiple touches
|
||||
* @param touches
|
||||
* @return {Object}
|
||||
*/
|
||||
getTouchCenter: function (touches) {
|
||||
return this.getVectorAvg(touches);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the average of multiple vectors (x, y values)
|
||||
*/
|
||||
getVectorAvg: function (vectors) {
|
||||
return {
|
||||
x: vectors.map(function (v) { return v.x; }).reduce(sum) / vectors.length,
|
||||
y: vectors.map(function (v) { return v.y; }).reduce(sum) / vectors.length
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an offset
|
||||
* @param offset the offset to add
|
||||
* @return return true when the offset change was accepted
|
||||
*/
|
||||
addOffset: function (offset) {
|
||||
this.offset = {
|
||||
x: this.offset.x + offset.x,
|
||||
y: this.offset.y + offset.y
|
||||
};
|
||||
},
|
||||
|
||||
sanitize: function () {
|
||||
if (this.zoomFactor < this.options.zoomOutFactor) {
|
||||
this.zoomOutAnimation();
|
||||
} else if (this.isInsaneOffset(this.offset)) {
|
||||
this.sanitizeOffsetAnimation();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the offset is ok with the current zoom factor
|
||||
* @param offset
|
||||
* @return {Boolean}
|
||||
*/
|
||||
isInsaneOffset: function (offset) {
|
||||
var sanitizedOffset = this.sanitizeOffset(offset);
|
||||
return sanitizedOffset.x !== offset.x ||
|
||||
sanitizedOffset.y !== offset.y;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates an animation moving to a sane offset
|
||||
*/
|
||||
sanitizeOffsetAnimation: function () {
|
||||
var targetOffset = this.sanitizeOffset(this.offset),
|
||||
startOffset = {
|
||||
x: this.offset.x,
|
||||
y: this.offset.y
|
||||
},
|
||||
updateProgress = (function (progress) {
|
||||
this.offset.x = startOffset.x + progress * (targetOffset.x - startOffset.x);
|
||||
this.offset.y = startOffset.y + progress * (targetOffset.y - startOffset.y);
|
||||
this.update();
|
||||
}).bind(this);
|
||||
|
||||
this.animate(
|
||||
this.options.animationDuration,
|
||||
updateProgress,
|
||||
this.swing
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Zooms back to the original position,
|
||||
* (no offset and zoom factor 1)
|
||||
*/
|
||||
zoomOutAnimation: function () {
|
||||
if (this.zoomFactor === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var startZoomFactor = this.zoomFactor,
|
||||
zoomFactor = 1,
|
||||
center = this.getCurrentZoomCenter(),
|
||||
updateProgress = (function (progress) {
|
||||
this.scaleTo(startZoomFactor + progress * (zoomFactor - startZoomFactor), center);
|
||||
}).bind(this);
|
||||
|
||||
this.animate(
|
||||
this.options.animationDuration,
|
||||
updateProgress,
|
||||
this.swing
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the container aspect ratio
|
||||
*
|
||||
* Any previous container height must be cleared before re-measuring the
|
||||
* parent height, since it depends implicitly on the height of any of its children
|
||||
*/
|
||||
updateAspectRatio: function () {
|
||||
this.unsetContainerY();
|
||||
this.setContainerY(this.container.parentElement.offsetHeight);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the initial zoom factor (for the element to fit into the container)
|
||||
* @return {number} the initial zoom factor
|
||||
*/
|
||||
getInitialZoomFactor: function () {
|
||||
var xZoomFactor = this.container.offsetWidth / this.el.offsetWidth;
|
||||
var yZoomFactor = this.container.offsetHeight / this.el.offsetHeight;
|
||||
|
||||
return Math.min(xZoomFactor, yZoomFactor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the aspect ratio of the element
|
||||
* @return the aspect ratio
|
||||
*/
|
||||
getAspectRatio: function () {
|
||||
return this.el.offsetWidth / this.el.offsetHeight;
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculates the virtual zoom center for the current offset and zoom factor
|
||||
* (used for reverse zoom)
|
||||
* @return {Object} the current zoom center
|
||||
*/
|
||||
getCurrentZoomCenter: function () {
|
||||
var offsetLeft = this.offset.x - this.initialOffset.x;
|
||||
var centerX = -1 * this.offset.x - offsetLeft / (1 / this.zoomFactor - 1);
|
||||
|
||||
var offsetTop = this.offset.y - this.initialOffset.y;
|
||||
var centerY = -1 * this.offset.y - offsetTop / (1 / this.zoomFactor - 1);
|
||||
|
||||
return {
|
||||
x: centerX,
|
||||
y: centerY
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the touches of an event relative to the container offset
|
||||
* @param event
|
||||
* @return array touches
|
||||
*/
|
||||
getTouches: function (event) {
|
||||
var rect = this.container.getBoundingClientRect();
|
||||
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
|
||||
var posTop = rect.top + scrollTop;
|
||||
var posLeft = rect.left + scrollLeft;
|
||||
|
||||
return Array.prototype.slice.call(event.touches).map(function (touch) {
|
||||
return {
|
||||
x: touch.pageX - posLeft,
|
||||
y: touch.pageY - posTop,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Animation loop
|
||||
* does not support simultaneous animations
|
||||
* @param duration
|
||||
* @param framefn
|
||||
* @param timefn
|
||||
* @param callback
|
||||
*/
|
||||
animate: function (duration, framefn, timefn, callback) {
|
||||
var startTime = new Date().getTime(),
|
||||
renderFrame = (function () {
|
||||
if (!this.inAnimation) { return; }
|
||||
var frameTime = new Date().getTime() - startTime,
|
||||
progress = frameTime / duration;
|
||||
if (frameTime >= duration) {
|
||||
framefn(1);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
this.update();
|
||||
this.stopAnimation();
|
||||
this.update();
|
||||
} else {
|
||||
if (timefn) {
|
||||
progress = timefn(progress);
|
||||
}
|
||||
framefn(progress);
|
||||
this.update();
|
||||
requestAnimationFrame(renderFrame);
|
||||
}
|
||||
}).bind(this);
|
||||
this.inAnimation = true;
|
||||
requestAnimationFrame(renderFrame);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stops the animation
|
||||
*/
|
||||
stopAnimation: function () {
|
||||
this.inAnimation = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Swing timing function for animations
|
||||
* @param p
|
||||
* @return {Number}
|
||||
*/
|
||||
swing: function (p) {
|
||||
return -Math.cos(p * Math.PI) / 2 + 0.5;
|
||||
},
|
||||
|
||||
getContainerX: function () {
|
||||
return this.container.offsetWidth;
|
||||
},
|
||||
|
||||
getContainerY: function () {
|
||||
return this.container.offsetHeight;
|
||||
},
|
||||
|
||||
setContainerY: function (y) {
|
||||
return this.container.style.height = y + 'px';
|
||||
},
|
||||
|
||||
unsetContainerY: function () {
|
||||
this.container.style.height = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the expected html structure
|
||||
*/
|
||||
setupMarkup: function () {
|
||||
this.container = buildElement('<div class="pinch-zoom-container"></div>');
|
||||
this.el.parentNode.insertBefore(this.container, this.el);
|
||||
this.container.appendChild(this.el);
|
||||
|
||||
this.container.style.overflow = 'hidden';
|
||||
this.container.style.position = 'relative';
|
||||
|
||||
this.el.style.webkitTransformOrigin = '0% 0%';
|
||||
this.el.style.mozTransformOrigin = '0% 0%';
|
||||
this.el.style.msTransformOrigin = '0% 0%';
|
||||
this.el.style.oTransformOrigin = '0% 0%';
|
||||
this.el.style.transformOrigin = '0% 0%';
|
||||
|
||||
this.el.style.position = 'absolute';
|
||||
},
|
||||
|
||||
end: function () {
|
||||
this.hasInteraction = false;
|
||||
this.sanitize();
|
||||
this.update();
|
||||
},
|
||||
|
||||
/**
|
||||
* Binds all required event listeners
|
||||
*/
|
||||
bindEvents: function () {
|
||||
var self = this;
|
||||
detectGestures(this.container, this);
|
||||
|
||||
this.resizeHandler = this.update.bind(this)
|
||||
window.addEventListener('resize', this.resizeHandler);
|
||||
Array.from(this.el.querySelectorAll('img')).forEach(function(imgEl) {
|
||||
imgEl.addEventListener('load', self.update.bind(self));
|
||||
});
|
||||
|
||||
if (this.el.nodeName === 'IMG') {
|
||||
this.el.addEventListener('load', this.update.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the css values according to the current zoom factor and offset
|
||||
*/
|
||||
update: function (event) {
|
||||
if (event && event.type === 'resize') {
|
||||
this.updateAspectRatio();
|
||||
this.setupOffsets();
|
||||
}
|
||||
|
||||
if (event && event.type === 'load') {
|
||||
this.updateAspectRatio();
|
||||
this.setupOffsets();
|
||||
}
|
||||
|
||||
if (this.updatePlanned) {
|
||||
return;
|
||||
}
|
||||
this.updatePlanned = true;
|
||||
|
||||
window.setTimeout((function () {
|
||||
this.updatePlanned = false;
|
||||
|
||||
var zoomFactor = this.getInitialZoomFactor() * this.zoomFactor,
|
||||
offsetX = -this.offset.x / zoomFactor,
|
||||
offsetY = -this.offset.y / zoomFactor,
|
||||
transform3d = 'scale3d(' + zoomFactor + ', ' + zoomFactor + ',1) ' +
|
||||
'translate3d(' + offsetX + 'px,' + offsetY + 'px,0px)',
|
||||
transform2d = 'scale(' + zoomFactor + ', ' + zoomFactor + ') ' +
|
||||
'translate(' + offsetX + 'px,' + offsetY + 'px)',
|
||||
removeClone = (function () {
|
||||
if (this.clone) {
|
||||
this.clone.parentNode.removeChild(this.clone);
|
||||
delete this.clone;
|
||||
}
|
||||
}).bind(this);
|
||||
|
||||
// Scale 3d and translate3d are faster (at least on ios)
|
||||
// but they also reduce the quality.
|
||||
// PinchZoom uses the 3d transformations during interactions
|
||||
// after interactions it falls back to 2d transformations
|
||||
if (!this.options.use2d || this.hasInteraction || this.inAnimation) {
|
||||
this.is3d = true;
|
||||
removeClone();
|
||||
|
||||
this.el.style.webkitTransform = transform3d;
|
||||
this.el.style.mozTransform = transform2d;
|
||||
this.el.style.msTransform = transform2d;
|
||||
this.el.style.oTransform = transform2d;
|
||||
this.el.style.transform = transform3d;
|
||||
} else {
|
||||
// When changing from 3d to 2d transform webkit has some glitches.
|
||||
// To avoid this, a copy of the 3d transformed element is displayed in the
|
||||
// foreground while the element is converted from 3d to 2d transform
|
||||
if (this.is3d) {
|
||||
this.clone = this.el.cloneNode(true);
|
||||
this.clone.style.pointerEvents = 'none';
|
||||
this.container.appendChild(this.clone);
|
||||
window.setTimeout(removeClone, 200);
|
||||
}
|
||||
|
||||
this.el.style.webkitTransform = transform2d;
|
||||
this.el.style.mozTransform = transform2d;
|
||||
this.el.style.msTransform = transform2d;
|
||||
this.el.style.oTransform = transform2d;
|
||||
this.el.style.transform = transform2d;
|
||||
|
||||
this.is3d = false;
|
||||
}
|
||||
}).bind(this), 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enables event handling for gestures
|
||||
*/
|
||||
enable: function() {
|
||||
this.enabled = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables event handling for gestures
|
||||
*/
|
||||
disable: function() {
|
||||
this.enabled = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Unmounts the zooming container and global event listeners
|
||||
*/
|
||||
destroy: function () {
|
||||
window.removeEventListener('resize', this.resizeHandler);
|
||||
|
||||
if (this.container) {
|
||||
this.container.remove();
|
||||
this.container = null;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var detectGestures = function (el, target) {
|
||||
var interaction = null,
|
||||
fingers = 0,
|
||||
lastTouchStart = null,
|
||||
startTouches = null,
|
||||
|
||||
setInteraction = function (newInteraction, event) {
|
||||
if (interaction !== newInteraction) {
|
||||
|
||||
if (interaction && !newInteraction) {
|
||||
switch (interaction) {
|
||||
case "zoom":
|
||||
target.handleZoomEnd(event);
|
||||
break;
|
||||
case 'drag':
|
||||
target.handleDragEnd(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (newInteraction) {
|
||||
case 'zoom':
|
||||
target.handleZoomStart(event);
|
||||
break;
|
||||
case 'drag':
|
||||
target.handleDragStart(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
interaction = newInteraction;
|
||||
},
|
||||
|
||||
updateInteraction = function (event) {
|
||||
if (fingers === 2) {
|
||||
setInteraction('zoom');
|
||||
} else if (fingers === 1 && target.canDrag()) {
|
||||
setInteraction('drag', event);
|
||||
} else {
|
||||
setInteraction(null, event);
|
||||
}
|
||||
},
|
||||
|
||||
targetTouches = function (touches) {
|
||||
return Array.from(touches).map(function (touch) {
|
||||
return {
|
||||
x: touch.pageX,
|
||||
y: touch.pageY
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
getDistance = function (a, b) {
|
||||
var x, y;
|
||||
x = a.x - b.x;
|
||||
y = a.y - b.y;
|
||||
return Math.sqrt(x * x + y * y);
|
||||
},
|
||||
|
||||
calculateScale = function (startTouches, endTouches) {
|
||||
var startDistance = getDistance(startTouches[0], startTouches[1]),
|
||||
endDistance = getDistance(endTouches[0], endTouches[1]);
|
||||
return endDistance / startDistance;
|
||||
},
|
||||
|
||||
cancelEvent = function (event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
},
|
||||
|
||||
detectDoubleTap = function (event) {
|
||||
var time = (new Date()).getTime();
|
||||
|
||||
if (fingers > 1) {
|
||||
lastTouchStart = null;
|
||||
}
|
||||
|
||||
if (time - lastTouchStart < 300) {
|
||||
cancelEvent(event);
|
||||
|
||||
target.handleDoubleTap(event);
|
||||
switch (interaction) {
|
||||
case "zoom":
|
||||
target.handleZoomEnd(event);
|
||||
break;
|
||||
case 'drag':
|
||||
target.handleDragEnd(event);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
target.isDoubleTap = false;
|
||||
}
|
||||
|
||||
if (fingers === 1) {
|
||||
lastTouchStart = time;
|
||||
}
|
||||
},
|
||||
firstMove = true;
|
||||
|
||||
el.addEventListener('touchstart', function (event) {
|
||||
if(target.enabled) {
|
||||
firstMove = true;
|
||||
fingers = event.touches.length;
|
||||
detectDoubleTap(event);
|
||||
}
|
||||
}, { passive: false });
|
||||
|
||||
el.addEventListener('touchmove', function (event) {
|
||||
if(target.enabled && !target.isDoubleTap) {
|
||||
if (firstMove) {
|
||||
updateInteraction(event);
|
||||
if (interaction) {
|
||||
cancelEvent(event);
|
||||
}
|
||||
startTouches = targetTouches(event.touches);
|
||||
} else {
|
||||
switch (interaction) {
|
||||
case 'zoom':
|
||||
if (startTouches.length == 2 && event.touches.length == 2) {
|
||||
target.handleZoom(event, calculateScale(startTouches, targetTouches(event.touches)));
|
||||
}
|
||||
break;
|
||||
case 'drag':
|
||||
target.handleDrag(event);
|
||||
break;
|
||||
}
|
||||
if (interaction) {
|
||||
cancelEvent(event);
|
||||
target.update();
|
||||
}
|
||||
}
|
||||
|
||||
firstMove = false;
|
||||
}
|
||||
}, { passive: false });
|
||||
|
||||
el.addEventListener('touchend', function (event) {
|
||||
if(target.enabled) {
|
||||
fingers = event.touches.length;
|
||||
updateInteraction(event);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return PinchZoom;
|
||||
};
|
||||
|
||||
var PinchZoom = definePinchZoom();
|
||||
|
||||
export default PinchZoom;
|
||||
@@ -0,0 +1,62 @@
|
||||
<script>
|
||||
module.exports = {
|
||||
name: "TableColumn",
|
||||
props: {
|
||||
label: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
value: {
|
||||
type: [String, Number],
|
||||
required: false
|
||||
},
|
||||
label_suffix:{
|
||||
type: String,
|
||||
default: ":"
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="table-column">
|
||||
<!-- 左侧 Label -->
|
||||
<div class="label">
|
||||
<slot name="label">
|
||||
{{ label }}
|
||||
{{label_suffix}}
|
||||
</slot>
|
||||
</div>
|
||||
<!-- 右侧 Value -->
|
||||
<div class="value">
|
||||
<slot>{{ value }}</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.table-column {
|
||||
display: flex;
|
||||
padding: 6px 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
flex-shrink: 0;
|
||||
max-width: 120px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #555;
|
||||
font-size: 14px;
|
||||
flex-grow: 1; /* 动态占据剩余部分 */
|
||||
white-space: nowrap; /* 防止换行 */
|
||||
overflow: hidden; /* 隐藏溢出的部分 */
|
||||
text-overflow: ellipsis; /* 省略号 */
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,278 @@
|
||||
<template>
|
||||
<van-pull-refresh v-model="tableRefreshing" @refresh="onRefresh">
|
||||
<div v-if="tableData.length === 0" class="empty-state">
|
||||
<van-empty description="暂无数据"></van-empty>
|
||||
</div>
|
||||
<van-list v-if="tableData && tableData.length>0"
|
||||
v-model="tableLoading"
|
||||
:finished="tableFinished"
|
||||
finished-text="没有更多了"
|
||||
@load="onLoad">
|
||||
<div class="table-list-container">
|
||||
<div v-for="(row, index) in tableData" :key="index" class="table-list-item">
|
||||
<slot name="header" :index="index" :row="row">
|
||||
<div class="item-header">
|
||||
<div class="item-title">{{ row[title] }}</div>
|
||||
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message"
|
||||
size="small"></enum-tag>
|
||||
</div>
|
||||
</slot>
|
||||
|
||||
<div style="display: flex;column-gap: 10px"
|
||||
:style="{'max-height':img ? '100px':'unset', 'overflow': img ? 'hidden':'unset' }">
|
||||
<div class="img-container" v-if="img">
|
||||
<img :src="row[img]" alt="" style="object-fit: cover">
|
||||
</div>
|
||||
<div class="">
|
||||
<slot :index="index" :row="row"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-actions">
|
||||
<slot name="actions" :index="index" :row="row"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</van-list>
|
||||
</van-pull-refresh>
|
||||
</template>
|
||||
<script>
|
||||
module.exports = {
|
||||
name: "TableList",
|
||||
props: {
|
||||
api: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
page_form: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => {
|
||||
return {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
searchKeyword: ""
|
||||
}
|
||||
}
|
||||
},
|
||||
json: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
img: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
page_form: {
|
||||
handler(newVal, oldVal) {
|
||||
this.localPageForm = { ...newVal }
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
tableLoading: false,
|
||||
tableFinished: false,
|
||||
tableRefreshing: false,
|
||||
localPageForm: { ...this.page_form }
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onLoad() {
|
||||
if (this.tableFinished) return
|
||||
this.localPageForm.pageNumber++
|
||||
this.$emit("update:page_form", { ...this.localPageForm })
|
||||
this.pageData()
|
||||
},
|
||||
|
||||
pageData() {
|
||||
this.tableLoading = true
|
||||
|
||||
const loading = createListLoading()
|
||||
this.$axios.post(this.api, this.json ? ({ pageForm: JSON.stringify(this.localPageForm) }) : this.localPageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = this.tableData.concat(res.data.list)
|
||||
this.localPageForm.totalCount = res.data.totalCount
|
||||
if (this.tableData.length >= this.localPageForm.totalCount) {
|
||||
this.tableFinished = true
|
||||
}
|
||||
this.$emit("update:page_form", { ...this.localPageForm })
|
||||
}
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
console.log(this.tableLoading)
|
||||
this.tableLoading = false
|
||||
console.log(this.tableLoading)
|
||||
this.tableRefreshing = false
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.tableFinished = false
|
||||
this.tableData = []
|
||||
this.localPageForm.pageNumber = 1
|
||||
this.$emit("update:page_form", { ...this.localPageForm })
|
||||
this.pageData()
|
||||
},
|
||||
onRefresh() {
|
||||
this.localPageForm.pageNumber = 1
|
||||
this.$emit("update:page_form", { ...this.localPageForm })
|
||||
this.doSearch()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$emit("ready")
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.table-list-container {
|
||||
padding: 0;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #eaecef;
|
||||
padding: 16px;
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .item-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #1f2f3d;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .img-container {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .img-container img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
|
||||
.table-list-container .table-list-item .item-meta {
|
||||
display: flex;
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
margin-bottom: 5px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .meta-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .meta-item i {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
width: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .item-content {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .item-footer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 12px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px dashed #eaecef;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .item-actions {
|
||||
display: flex;
|
||||
column-gap: 20px;
|
||||
justify-content: end;
|
||||
margin-top: 15px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #eaecef;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .action-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
font-size: 14px;
|
||||
color: var(--color-primary);
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .action-btn i {
|
||||
margin-right: 6px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .action-btn.delete {
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
.table-list-container .table-list-item .action-btn.review {
|
||||
color: #67c23a;
|
||||
}
|
||||
|
||||
.table-list-container .empty-state {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.table-list-container .empty-state i {
|
||||
font-size: 60px;
|
||||
margin-bottom: 16px;
|
||||
color: #dcdee0;
|
||||
}
|
||||
|
||||
.table-list-container .empty-state p {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div>
|
||||
<template v-for="item in options">
|
||||
<component :key="item[value_key]" v-if="item[value_key] === value" v-bind="$attrs"
|
||||
:is="isMobile ? 'van-tag' : 'el-tag'" :type="item.type"
|
||||
>{{ item[label_key] }}
|
||||
</component>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 全局缓存和请求Promise缓存
|
||||
const enumCache = {}
|
||||
const requestPromises = {}
|
||||
|
||||
module.exports = {
|
||||
name: "DictTag",
|
||||
props: {
|
||||
value: { type: String | Number },
|
||||
name: { type: String },
|
||||
value_key: {
|
||||
type: String,
|
||||
default: "code"
|
||||
},
|
||||
label_key: {
|
||||
type: String,
|
||||
default: "name"
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
options: [],
|
||||
isMobile: true,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
code: {
|
||||
handler(val) {
|
||||
this.getEnumOptions()
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isMobileDevice() {
|
||||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
||||
navigator.userAgent
|
||||
);
|
||||
},
|
||||
getEnumOptions() {
|
||||
// // 检查数据缓存
|
||||
// if (enumCache[this.name]) {
|
||||
// this.options = enumCache[this.name]
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // 检查是否已有相同请求在进行中
|
||||
// if (requestPromises[this.name]) {
|
||||
// requestPromises[this.name].then(data => {
|
||||
// this.options = data
|
||||
// })
|
||||
// return
|
||||
// }
|
||||
|
||||
// 创建请求Promise并缓存
|
||||
requestPromises[this.name] = $.get("/open/common/dictEnumOptions", { name: this.name })
|
||||
.then(res => {
|
||||
if (res.code === 0) {
|
||||
// 存入数据缓存
|
||||
enumCache[this.name] = res.data
|
||||
// 清除请求Promise缓存
|
||||
delete requestPromises[this.name]
|
||||
return res.data
|
||||
}
|
||||
})
|
||||
|
||||
requestPromises[this.name].then(data => {
|
||||
this.options = data
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.isMobile = this.isMobileDevice()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-tag + .el-tag {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.van-tag {
|
||||
height: 24px;
|
||||
padding: 0 8px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.van-tag--success {
|
||||
background-color: #f0f9eb;
|
||||
border-color: #e1f3d8;
|
||||
color: #67c23a;
|
||||
}
|
||||
.van-tag--primary {
|
||||
color: var(--color-primary);
|
||||
background-color: #ecf5ff;
|
||||
border-color: #d9ecff;
|
||||
}
|
||||
.van-tag--danger{
|
||||
background-color: #fef0f0;
|
||||
border-color: #fde2e2;
|
||||
color: #f56c6c;
|
||||
}
|
||||
.van-tag--warning{
|
||||
background-color: #fdf6ec;
|
||||
border-color: #faecd8;
|
||||
color: #e6a23c;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="pdf" id="pdf-container"></div>
|
||||
<div v-else v-html="content" class="content"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
module.exports = {
|
||||
name: "PdfIndex",
|
||||
props: {
|
||||
content: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 300,
|
||||
required: false
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pdf: true,
|
||||
pdfObj: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
try {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(this.content, 'text/html');
|
||||
const link = doc.querySelector('a');
|
||||
const href = link.getAttribute('href');
|
||||
this.$nextTick(() => {
|
||||
this.pdfObj = new Pdfh5('#pdf-container', {
|
||||
pdfurl: href,
|
||||
});
|
||||
this.pdfObj.on("complete", function () {
|
||||
const elements = document.querySelectorAll('[class*="canvasImg"]')
|
||||
let classArray = []
|
||||
elements.forEach(element => {
|
||||
classArray.push(element.getAttribute('src'))
|
||||
})
|
||||
elements.forEach((element,index) => {
|
||||
element.addEventListener('click', function() {
|
||||
vant.ImagePreview({
|
||||
images: classArray,
|
||||
startPosition: index,
|
||||
closeable: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}catch (e) {
|
||||
this.pdf = false
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.content {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div class="sign-container">
|
||||
<template v-if="Object.keys(res).length === 0">
|
||||
<div class="reader-container">
|
||||
<div id="reader"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="weui-msg">
|
||||
<div class="weui-msg__icon-area">
|
||||
<i v-if="res?.code !== 0" class="weui-icon-warn weui-icon_msg"></i>
|
||||
<i v-if="res?.code === 0" class="weui-icon-success weui-icon_msg"></i>
|
||||
</div>
|
||||
<div class="weui-msg__text-area">
|
||||
<div class="weui-msg__title">温馨提醒</div>
|
||||
<div v-html="res?.msg"></div>
|
||||
</div>
|
||||
<div class="weui-msg__opr-area">
|
||||
<p class="weui-btn-area">
|
||||
<a @click="res = {}; getCameras()"
|
||||
class="weui-btn weui-btn_primary">重新扫描</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
module.exports = {
|
||||
name: "scanCode",
|
||||
props: {
|
||||
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
html5QrCode: null,
|
||||
scanStatus: true,
|
||||
cameraId: '',
|
||||
res: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCameras() {
|
||||
Html5Qrcode.getCameras()
|
||||
.then((devices) => {
|
||||
if (devices && devices.length) {
|
||||
// 如果有2个摄像头,1为前置的
|
||||
if (devices.length > 1) {
|
||||
this.cameraId = devices[1].id;
|
||||
} else {
|
||||
this.cameraId = devices[0].id;
|
||||
}
|
||||
let isHuawei = navigator.userAgent.toLowerCase().match(/huawei/i) === 'huawei';
|
||||
if(isHuawei) {
|
||||
const backCamera = devices.filter(o => o.label.includes('back'))
|
||||
this.cameraId = backCamera[0].id;
|
||||
}
|
||||
this.start();
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
},
|
||||
start() {
|
||||
this.html5QrCode = new Html5Qrcode("reader");
|
||||
this.html5QrCode.start(
|
||||
this.cameraId, // retreived in the previous step.
|
||||
{
|
||||
fps: 100, // sets the framerate to 10 frame per second,
|
||||
qrbox: {width: 1000, height: 1000}, // sets only 250 X 250 region of viewfinder to
|
||||
},
|
||||
async (decodedText, decodedResult) => {
|
||||
this.res = await this.$axios.post(decodedText)
|
||||
this.closeScan()
|
||||
},
|
||||
(errorMessage) => {
|
||||
console.log(errorMessage);
|
||||
}
|
||||
)
|
||||
.catch((err) => {
|
||||
alert(err)
|
||||
console.log(`Unable to start scanning, error: ` + err);
|
||||
});
|
||||
},
|
||||
closeScan() {
|
||||
this.html5QrCode.stop()
|
||||
.then((ignore) => {
|
||||
console.log("QR Code scanning stopped.");
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Unable to stop scanning.");
|
||||
});
|
||||
},
|
||||
init() {
|
||||
this.getCameras()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sign-container{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.reader-container {
|
||||
padding-top: 50px;
|
||||
}
|
||||
#reader {
|
||||
width: 90%;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
.weui-msg__icon-area {
|
||||
margin-top: 30px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user