Merge branch 'main' of https://dd3skj.picp.vip/zhaoxinyu/v4
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+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;
|
||||
@@ -38,6 +38,7 @@ module.exports = {
|
||||
.table-column {
|
||||
display: flex;
|
||||
padding: 6px 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.label {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
@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" v-if="$slots.header">
|
||||
<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"
|
||||
|
||||
@@ -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>
|
||||
@@ -8,6 +8,67 @@
|
||||
<script>
|
||||
const { $, BtnMenu, Panel, Tooltip } = wangEditor
|
||||
|
||||
class PDFMenu extends BtnMenu {
|
||||
constructor(editor) {
|
||||
const $elem = wangEditor.$(
|
||||
`<div class="w-e-menu" data-title="上传pdf">
|
||||
<i class="fa fa-file-pdf-o" aria-hidden="true" /></i>
|
||||
</div>`
|
||||
)
|
||||
super($elem, editor)
|
||||
}
|
||||
|
||||
clickHandler() {
|
||||
const _this = this
|
||||
const inputFileElement = document.querySelector('#'+this.editor.textElemId).parentElement.parentElement.nextElementSibling
|
||||
inputFileElement.click()
|
||||
inputFileElement.addEventListener('change', function () {
|
||||
const file = this.files[0];
|
||||
const fileName = file.name
|
||||
|
||||
if (!fileName.toLowerCase().endsWith('.pdf')) {
|
||||
alert('请上传pdf格式的文件')
|
||||
_this.clearInputFile()
|
||||
return
|
||||
}
|
||||
|
||||
const formData = new FormData()
|
||||
formData.append('file', file, file.name)
|
||||
/*axios.post("/platform/sys/file/uploadDynamicReturnUrl", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data"
|
||||
}
|
||||
})*/
|
||||
axios.post("/platform/sys/file/uploadDynamicReturnUrl", formData, {}).then(response => {
|
||||
console.log(response.data)
|
||||
if (response.data.code === 0) {
|
||||
const html = `<a target="_blank" href="${window.location.origin}${response.data.data}">
|
||||
${file.name}
|
||||
</a>`
|
||||
_this.editor.txt.html(html)
|
||||
} else {
|
||||
alert(response.data.msg + ',上传pdf失败,请联系管理员!')
|
||||
_this.clearInputFile()
|
||||
}
|
||||
}).catch(error => {
|
||||
console.log(error)
|
||||
_this.clearInputFile()
|
||||
alert('上传pdf失败,请联系管理员!')
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
clearInputFile() {
|
||||
const obj = document.getElementById('fileInput');
|
||||
obj.outerHTML = obj.outerHTML
|
||||
}
|
||||
|
||||
tryChangeActive() {
|
||||
this.active()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//注册上传word按钮
|
||||
class DocMenu extends BtnMenu {
|
||||
constructor(editor) {
|
||||
@@ -90,6 +151,7 @@ class DocMenu extends BtnMenu {
|
||||
}
|
||||
|
||||
wangEditor.registerMenu("docMenu", DocMenu)
|
||||
wangEditor.registerMenu('pdfMenuKey', PDFMenu)
|
||||
module.exports = {
|
||||
name: "textEditor",
|
||||
props: {
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/h5.css"/>
|
||||
<link rel="stylesheet" href="https://cdn.staticfile.net/animate.css/4.1.1/animate.css"/>
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/fonts/font-awesome.min.css"/>
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/css/pdf/pdfh5.css">
|
||||
<link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/2.2.0/weui.min.css">
|
||||
|
||||
<script src="${base!}/assets/platform/plugins/vue/vue.js"></script>
|
||||
<script src="${base!}/assets/platform/plugins/vuex/vuex.js"></script>
|
||||
@@ -43,6 +45,14 @@
|
||||
<link rel="stylesheet" href="${base!}/assets/platform/plugins/viewerjs/viewer.css" />
|
||||
<script src="${base!}/assets/platform/plugins/viewerjs/viewer.js"></script>
|
||||
|
||||
<!--pdf平铺展示-->
|
||||
<script src="${base!}/assets/platform/plugins/pdfJs/h5/pdf.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="${base!}/assets/platform/plugins/pdfJs/h5/pdf.worker.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="${base!}/assets/platform/plugins/pdfJs/h5/pdfh5.js" type="text/javascript" charset="utf-8"></script>
|
||||
|
||||
<!--h5扫码-->
|
||||
<script src="${base!}/assets/platform/plugins/html5-qrcode/html5-qrcode.min.js"></script>
|
||||
|
||||
<script src="${base!}/components/plugins/sysDict/DictData.js"></script>
|
||||
<script src="${base!}/assets/platform/js/util/commonUtil.js"></script>
|
||||
<script src="${base!}/assets/platform/js/main.js"></script>
|
||||
|
||||
+39
-45
@@ -1,4 +1,4 @@
|
||||
const signForm = {
|
||||
const applyForm = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<el-dialog :close-on-click-modal="false" :visible.sync="signDialog" title="信息填写" width="50%" append-to-body>
|
||||
@@ -33,11 +33,11 @@ const signForm = {
|
||||
<el-input readonly v-model="formData.sex"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<!--<el-col :span="24">
|
||||
<el-form-item label="联系方式" prop="mobile">
|
||||
<el-input v-model="formData.mobile"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-col>-->
|
||||
</el-row>
|
||||
|
||||
<el-row v-if="courseRow.courseIsLimitApply">
|
||||
@@ -121,7 +121,7 @@ const signForm = {
|
||||
},
|
||||
methods: {
|
||||
async getCourseTimeSelectList(o) {
|
||||
const resp = await $.post('/platform/mobile/trainSignUpActivity/getCourseTimeSelectList',{ courseId: o.id })
|
||||
const resp = await $.post('/platform/trainSingUp/apply/getCourseTimeSelectList',{ courseId: o.id })
|
||||
if (resp.code === 0) {
|
||||
this.courseTimeSelectList = resp.data
|
||||
} else {
|
||||
@@ -135,35 +135,34 @@ const signForm = {
|
||||
}
|
||||
this.courseRow = row
|
||||
this.signDialog = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.form.clearValidate()
|
||||
})
|
||||
},
|
||||
async validateSignUp() {
|
||||
// 获取家属人数
|
||||
let familyCount = this.formData.trainMobileSignColumnList.filter(o => o.columnCode === 'xdqsrs').reduce((sum, item) => {
|
||||
return sum + (Number(item.columnValue) || 0)
|
||||
}, 0)
|
||||
const res = await this.$axios.post("/platform/trainSingUp/apply/validateSignUp", {
|
||||
courseId: this.formData.courseId,
|
||||
currentFamilyNumber: familyCount
|
||||
})
|
||||
return res.code === 0
|
||||
},
|
||||
async validateCourseTime() {
|
||||
const res = await this.$axios.post('/platform/trainSingUp/apply/validateSourceSignUp', {
|
||||
activityCourseId: this.formData.activityCourseId,
|
||||
courseId: this.courseRow.id
|
||||
})
|
||||
return res.code === 0
|
||||
},
|
||||
async onSubmit() {
|
||||
//获取家属是多少人
|
||||
let per = 0
|
||||
this.formData.trainMobileSignColumnList.forEach((item) => {
|
||||
if (item.columnCode === "xdqsrs") {
|
||||
per += Number(item.columnValue)
|
||||
}
|
||||
})
|
||||
const res = await this.$axios.post("/platform/mobile/trainSignUpActivity/validateSignUp", {
|
||||
courseId: this.formData.courseId,
|
||||
currentFamilyNumber: per
|
||||
})
|
||||
if (res.code !== 0) {
|
||||
this.$message.warning(res.msg)
|
||||
return
|
||||
}
|
||||
if(!await this.validateSignUp()) return
|
||||
|
||||
this.$refs["form"].validate(async (valid) => {
|
||||
if (valid) {
|
||||
if (this.courseRow.courseIsLimitApply) {
|
||||
const resp = await this.$axios.post('/platform/mobile/trainSignUpActivity/validateSourceSignUp', {
|
||||
activityCourseId: this.formData.activityCourseId,
|
||||
courseId: this.courseRow.id
|
||||
})
|
||||
if (resp.code !== 0) {
|
||||
this.$message.warning(res.msg)
|
||||
return
|
||||
}
|
||||
}
|
||||
if(this.courseRow.courseIsLimitApply && !await this.validateCourseTime()) return
|
||||
this.$confirm("您确定要提交吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
@@ -178,7 +177,7 @@ const signForm = {
|
||||
}
|
||||
})
|
||||
this.formData.mobileColumnsValue = JSON.stringify(mobileColumnsValue)
|
||||
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/doSignUp", this.formData)
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/apply/doSignUp", this.formData)
|
||||
if (resp.code === 0) {
|
||||
this.signDialog = false
|
||||
this.$message.success(resp.msg)
|
||||
@@ -191,22 +190,17 @@ const signForm = {
|
||||
})
|
||||
},
|
||||
initData(row, course) {
|
||||
this.formData = {
|
||||
activityId: row.activityId,
|
||||
courseId: row.id,
|
||||
username: this.$store.state.user.username,
|
||||
loginname: this.$store.state.user.loginname,
|
||||
unionName: this.$store.state.user.union.name,
|
||||
unitName: this.$store.state.user.unit.name,
|
||||
sex: this.$store.state.user.sex,
|
||||
mobile: this.$store.state.user.mobile,
|
||||
trainMobileSignColumnList: course.trainMobileSignColumnList
|
||||
}
|
||||
this.$set(this.formData, 'username', this.$store.state.user.username)
|
||||
this.$set(this.formData, 'loginname', this.$store.state.user.loginname)
|
||||
this.$set(this.formData, 'unionName', this.$store.state.user.union.name)
|
||||
this.$set(this.formData, 'unitName', this.$store.state.user.unit.name)
|
||||
this.$set(this.formData, 'sex', this.$store.state.user.sex)
|
||||
this.$set(this.formData, 'activityId', row.activityId)
|
||||
this.$set(this.formData, 'courseId', row.id)
|
||||
this.$set(this.formData, 'trainMobileSignColumnList', course.trainMobileSignColumnList)
|
||||
|
||||
this.formData.trainMobileSignColumnList.forEach((item) => {
|
||||
item.columnValue = ""
|
||||
})
|
||||
this.$nextTick(() => {
|
||||
this.$refs.form.clearValidate()
|
||||
item.columnValue = this.$store.state.user[item.columnCode] || ""
|
||||
})
|
||||
},
|
||||
},
|
||||
+25
-9
@@ -1,5 +1,5 @@
|
||||
<!--#include('signForm.js'){}#-->
|
||||
const info = {
|
||||
<!--#include('applyForm.js'){}#-->
|
||||
const courseList = {
|
||||
template: /*language=HTML*/ `
|
||||
<div>
|
||||
<el-row :gutter="20">
|
||||
@@ -67,6 +67,11 @@ const info = {
|
||||
<template v-slot="{row}" v-else-if="column.prop=='applyNum'">
|
||||
<span v-html="calcSignUpCount(row)"></span>
|
||||
</template>
|
||||
|
||||
<template v-slot="{row}" v-else-if="column.prop=='introduce'">
|
||||
<span v-if="!row.introduce">暂无</span>
|
||||
<el-button v-else style="padding: 0" @click="onPreview(row.introduce)" type="text">点击查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100">
|
||||
<template v-slot="{row}">
|
||||
@@ -103,13 +108,13 @@ const info = {
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
|
||||
<sign-form ref="signFormRef" @refresh="doSearch"></sign-form>
|
||||
<apply-form ref="formRef" @refresh="doSearch"></apply-form>
|
||||
</div>
|
||||
`,
|
||||
dicts: ["TRAIN_SIGNUP_TYPE"],
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"sign-form": signForm,
|
||||
"apply-form": applyForm,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -125,6 +130,7 @@ const info = {
|
||||
{ prop: "typeName", label: "类型", width: 130},
|
||||
{ prop: "courseLocationCoordinates", label: "地点", width: 200 },
|
||||
{ prop: "courseInstructor", label: "联系人", width: 100 },
|
||||
{ prop: "introduce", label: "详细介绍", width: 100 },
|
||||
{ prop: "courseTime", label: "时间", width: 200 },
|
||||
{ prop: "applyNum", label: "已报名人数", width: 200 }
|
||||
],
|
||||
@@ -135,6 +141,17 @@ const info = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async onPreview(introduce) {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(introduce, 'text/html');
|
||||
const link = doc.querySelector('a');
|
||||
const href = link.getAttribute('href');
|
||||
|
||||
const id = href.substring(href.indexOf("=") + 1)
|
||||
const res = await this.$axios.post("/platform/sys/file/previewFileData", { ids: JSON.stringify([id]) })
|
||||
|
||||
window.open("/assets/platform/plugins/pdfJs/web/viewer.html?file=" + encodeURIComponent(res.data[0].downloadPath), res.data[0].name)
|
||||
},
|
||||
tagClick(key, val) {
|
||||
let idx = this.pageForm[key].indexOf(val)
|
||||
if (idx !== -1) {
|
||||
@@ -153,7 +170,7 @@ const info = {
|
||||
},
|
||||
onSign(row) {
|
||||
const course = this.courseTypeList.find((v) => v.id === row.courseType)
|
||||
this.$axios.post("/platform/mobile/trainSignUpActivity/validateSignUp", {courseId: row.id})
|
||||
this.$axios.post("/platform/trainSingUp/apply/validateSignUp", {courseId: row.id})
|
||||
.then((res) => {
|
||||
if (res.code !== 0) {
|
||||
this.$alert(res.msg, "提示", {
|
||||
@@ -168,7 +185,7 @@ const info = {
|
||||
type: "warning"
|
||||
})
|
||||
}
|
||||
this.$refs.signFormRef.onOpen(row, course)
|
||||
this.$refs.formRef.onOpen(row, course)
|
||||
}
|
||||
})
|
||||
},
|
||||
@@ -178,7 +195,7 @@ const info = {
|
||||
cancelButtonText: "取消",
|
||||
type: "info"
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post("/platform/mobile/trainSignUpActivity/cancelSignUp", {
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/apply/cancelSignUp", {
|
||||
activityId: row.activityId,
|
||||
courseId: row.id
|
||||
})
|
||||
@@ -191,7 +208,7 @@ const info = {
|
||||
})
|
||||
},
|
||||
async getCourseTypeList() {
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/type/getAllType")
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/type/getAllType")
|
||||
if (resp.code === 0) {
|
||||
this.courseTypeList = resp.data
|
||||
}
|
||||
@@ -246,7 +263,6 @@ const info = {
|
||||
}
|
||||
},
|
||||
queryCourseAssort() {
|
||||
console.log(this.activity)
|
||||
this.$axios.post(loc() + "/queryCourseAssort", {activityId: this.activity.id})
|
||||
.then((resp) => {
|
||||
this.assortList = resp.data
|
||||
@@ -21,15 +21,16 @@ layout("/layouts/platform.html"){
|
||||
></el-date-picker>
|
||||
</search-item>
|
||||
<search-item label="活动状态:" style="width: 340px">
|
||||
<el-radio-group v-model="pageForm.activityType" @change="doSearch">
|
||||
<el-radio-button :label="1">全部</el-radio-button>
|
||||
<el-radio-button :label="2">报名中</el-radio-button>
|
||||
<el-radio-button :label="3">已结束</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-select v-model="pageForm.activityType" @change="doSearch" style="width: 100%"
|
||||
placeholder="请选择活动状态" filterable>
|
||||
<el-option :value="1" label="全部"></el-option>
|
||||
<el-option :value="4" label="即将开始"></el-option>
|
||||
<el-option :value="2" label="报名中"></el-option>
|
||||
<el-option :value="3" label="已结束"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card class="mt10" shadow="never">
|
||||
<table-tool label="活动列表"></table-tool>
|
||||
<el-table :data="tableData" :size="tableSize">
|
||||
@@ -56,8 +57,9 @@ layout("/layouts/platform.html"){
|
||||
<span>{{$moment(row.activityEndTime).format('MM/DD HH:mm')}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100">
|
||||
<el-table-column label="操作" width="300">
|
||||
<template v-slot="{row}">
|
||||
<el-button @click="onView(row)" size="mini" type="primary">查看介绍</el-button>
|
||||
<el-button @click="onOpen(row)" size="mini" type="primary">去报名</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -66,24 +68,50 @@ layout("/layouts/platform.html"){
|
||||
</el-card>
|
||||
|
||||
<template #view>
|
||||
<info ref="infoRef"></info>
|
||||
<course-list ref="courseListRef"></course-list>
|
||||
</template>
|
||||
</guava>
|
||||
|
||||
<el-dialog title="详细信息" :visible.sync="infoVisible" width="60%">
|
||||
|
||||
<activity-info ref="infoRef"></activity-info>
|
||||
|
||||
<el-statistic
|
||||
v-if="time < 0"
|
||||
format="DD 天 HH 时 mm 分钟 ss 秒"
|
||||
:value="new Date(infoRow.activitySignUpStartTime)"
|
||||
time-indices
|
||||
title="距离开始:"
|
||||
@finish="time = 0"
|
||||
style="margin-top: 30px"
|
||||
>
|
||||
</el-statistic>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="infoVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onOpen(infoRow)" :disabled="time < 0">
|
||||
去报名
|
||||
</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
<!--#include('info.js'){}#-->
|
||||
<!--#include('courseList.js'){}#-->
|
||||
<!--#include('../manage/info.js'){}#-->
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
components: {
|
||||
"info": info,
|
||||
"course-list": courseList,
|
||||
"activity-info": info,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
year: this.$moment().format("YYYY"),
|
||||
activityType: "2"
|
||||
activityType: 2
|
||||
},
|
||||
tableColumns: [
|
||||
{ label: "活动名称", prop: "activityName", width: 600},
|
||||
@@ -91,16 +119,32 @@ layout("/layouts/platform.html"){
|
||||
{ label: "报名时间", prop: "activitySignUpStartTime"},
|
||||
{ label: "活动时间", prop: "activityStartTime"},
|
||||
],
|
||||
time: 0,
|
||||
infoRow: {},
|
||||
infoVisible: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.infoRow = row
|
||||
this.time = this.$moment().diff(this.$moment(row.activitySignUpStartTime), 'milliseconds')
|
||||
this.infoVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.infoRef.initData(row.id)
|
||||
})
|
||||
},
|
||||
onOpen(row) {
|
||||
if(this.$moment().isBefore(this.$moment(row.activitySignUpStartTime))) {
|
||||
this.onView(row)
|
||||
return
|
||||
}
|
||||
this.infoVisible = false
|
||||
this.$refs.guava.view(() => {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
this.$refs.courseListRef.onOpen(row)
|
||||
})
|
||||
},
|
||||
pageData() {
|
||||
this.$axios.post("/platform/trainSingUp/manage/apply/activityData", this.pageForm).then((res) => {
|
||||
this.$axios.post("/platform/trainSingUp/apply/activityPageData", this.pageForm).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
|
||||
@@ -371,7 +371,7 @@ const basicForm = {
|
||||
}
|
||||
},
|
||||
async getRegisterUserCount(courseId) {
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/getRegisterUserCount", { courseId })
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/getRegisterUserCount", { courseId })
|
||||
return resp.code === 0 ? resp.data : 0
|
||||
},
|
||||
courseTypeChange(val, row) {
|
||||
@@ -444,7 +444,7 @@ const basicForm = {
|
||||
this.formData.courseList.push({ courseTimeList: [], isMobileSign: false, isReceiveGift: false, reserveMode: 1, courseIsLimitApply: false })
|
||||
},
|
||||
async historicalActChange(val) {
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/findOne", {id: val})
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/findOne", {id: val})
|
||||
if (resp.code === 0) {
|
||||
this.formData = resp.data
|
||||
this.typeChange(this.formData.trainType)
|
||||
@@ -468,7 +468,7 @@ const basicForm = {
|
||||
return data
|
||||
},
|
||||
async getHistoricalActList() {
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/getHistoricalActList", {})
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/getHistoricalActList", {})
|
||||
return resp.data
|
||||
},
|
||||
async onSave() {
|
||||
@@ -543,7 +543,7 @@ const basicForm = {
|
||||
type: "warning"
|
||||
})
|
||||
if (confirm !== "confirm") return
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/doHandle", cloneData)
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/doHandle", cloneData)
|
||||
if (resp.code === 0) {
|
||||
this.$message.success(resp.msg)
|
||||
this.step = 1
|
||||
@@ -554,12 +554,12 @@ const basicForm = {
|
||||
}
|
||||
},
|
||||
async getAllType() {
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/type/getAllType", {})
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/type/getAllType", {})
|
||||
return resp.data
|
||||
},
|
||||
async init(row) {
|
||||
if (row && row.id) {
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/activity/findOne", {id: row.id})
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/findOne", {id: row.id})
|
||||
if (resp.code === 0) {
|
||||
this.formData = resp.data
|
||||
this.typeChange(this.formData.trainType)
|
||||
|
||||
@@ -140,6 +140,16 @@ const customForm = {
|
||||
v-model="formData.courseList[moreInfoIndex].waitingNum"></el-input-number>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="50" type="flex">
|
||||
<el-col :span="4">
|
||||
<span>详细信息</span>
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<text-editor v-model="formData.courseList[moreInfoIndex].introduce"></text-editor>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<div style="text-align: right">
|
||||
<el-button @click="moreInfoDrawer = false">取 消</el-button>
|
||||
<el-button type="primary" @click="moreInfoDrawer = false">保 存</el-button>
|
||||
@@ -195,17 +205,6 @@ const customForm = {
|
||||
}
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
.my-drawer .el-col-4 {
|
||||
text-align: right;
|
||||
}
|
||||
.my-drawer .el-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.el-drawer__body {
|
||||
padding: 20px;
|
||||
}
|
||||
.el-row--flex {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
@@ -3,7 +3,18 @@ layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
|
||||
.my-drawer .el-col-4 {
|
||||
text-align: right;
|
||||
}
|
||||
.my-drawer .el-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.el-drawer__body {
|
||||
padding: 20px;
|
||||
}
|
||||
.el-row--flex {
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
@@ -115,6 +126,7 @@ layout("/layouts/platform.html"){
|
||||
</guava>
|
||||
</div>
|
||||
|
||||
<script src="${base!}/assets/platform/plugins/jr-qrcode/jr-qrcode.js"></script>
|
||||
<script>
|
||||
<!--#include('info.js'){}#-->
|
||||
<!--#include('basicForm.js'){}#-->
|
||||
@@ -164,8 +176,7 @@ layout("/layouts/platform.html"){
|
||||
})
|
||||
},
|
||||
openActivityCode(id) {
|
||||
this.activityUrl = location.origin + "/platform/mobile/trainSignUpActivity/activityInfo?activityId="
|
||||
+ id + '&isMySign=0'
|
||||
this.activityUrl = location.origin + "/platform/trainSingUp/apply/h5?id=" + id
|
||||
this.codeDialogVisible = true
|
||||
},
|
||||
makeCode(row) {
|
||||
|
||||
@@ -66,7 +66,7 @@ const info = {
|
||||
},
|
||||
methods: {
|
||||
initData(id) {
|
||||
this.$axios.post(loc() + "/findOne", { id: id })
|
||||
this.$axios.post("/platform/trainSingUp/manage/findOne", { id: id })
|
||||
.then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
this.viewData = resp.data
|
||||
|
||||
@@ -66,8 +66,10 @@ const makeQrcode = {
|
||||
this.courseDialog = true
|
||||
},
|
||||
makeCourseCode(row) {
|
||||
const o = {courseId: row.id}
|
||||
const content = jrQrcode.getQrBase64(JSON.stringify(o))
|
||||
const url = '/platform/trainSingUp/mine/drivingScan'
|
||||
const data = url + '?courseId=' + row.id
|
||||
console.log(data)
|
||||
const content = jrQrcode.getQrBase64(data)
|
||||
let image = new Image()
|
||||
image.src = content
|
||||
let viewer = new Viewer(image, {
|
||||
|
||||
@@ -150,7 +150,7 @@ const unionForm = {
|
||||
!this.formData.courseList[this.unionLimitIndex].unionLimit ||
|
||||
this.formData.courseList[this.unionLimitIndex].unionLimit.length === 0
|
||||
) {
|
||||
const resp = await this.$axios.get("/platform/trainSingUp/manage/activity/getUnionLimit", {
|
||||
const resp = await this.$axios.get("/platform/trainSingUp/manage/getUnionLimit", {
|
||||
activityScopeId: this.formData.activityGroupId
|
||||
})
|
||||
if (resp.code === 0) {
|
||||
|
||||
@@ -212,7 +212,7 @@ layout("/layouts/platform.html"){
|
||||
await this.doSearch()
|
||||
},
|
||||
async getActivityList() {
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/statistics/activity/activityList", { year: this.pageForm.year })
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/statistics/activityList", { year: this.pageForm.year })
|
||||
this.activityList = resp.data
|
||||
if (this.activityList && this.activityList.length > 0) {
|
||||
this.pageForm.activityId = this.activityList[0].id
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
.info-title {
|
||||
font-weight: bold;
|
||||
background-color: white;
|
||||
padding: 13px;
|
||||
box-shadow: 0 8px 12px #ebedf0;
|
||||
text-align: center !important;
|
||||
}
|
||||
.info-container {
|
||||
height: calc(100vh - 46px - 44px);
|
||||
min-height: calc(100vh - 46px - 44px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.info-img {
|
||||
display: block;
|
||||
}
|
||||
.van-count-down {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app">
|
||||
<van-nav-bar title="品牌活动" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<van-sticky offset-top="46px">
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.activityType" :options="typeOptions" :multiple="false"
|
||||
@change="doSearch"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</van-sticky>
|
||||
|
||||
<table-list api="/platform/trainSingUp/apply/activityPageData"
|
||||
:page_form.sync="pageForm"
|
||||
ref="tableListRef"
|
||||
title="activityName"
|
||||
img="cover"
|
||||
@ready="onReady"
|
||||
>
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="面向对象">{{row.activityGroupName}}</table-column>
|
||||
<table-column label="报名时间">
|
||||
{{$moment(row.activitySignUpStartTime).format('MM/DD HH:mm') + '~' + $moment(row.activitySignUpEndTime).format('MM/DD HH:mm')}}
|
||||
</table-column>
|
||||
<table-column label="活动时间">
|
||||
{{$moment(row.activityStartTime).format('MM/DD HH:mm') + '~' + $moment(row.activityEndTime).format('MM/DD HH:mm')}}
|
||||
</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<span>查看介绍</span>
|
||||
</div>
|
||||
<div class="action-btn" @click="onApply(row)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<span>去报名</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<van-popup v-model="infoVisible" position="right" :style="{ width: '100%', height: '100%' }">
|
||||
<van-nav-bar title="详细信息" left-text="返回" left-arrow @click-left="infoVisible = false" fixed placeholder></van-nav-bar>
|
||||
|
||||
<div class="info-container">
|
||||
<van-image class="info-img" height="186" width="100%" :src="infoRow.cover"></van-image>
|
||||
<div class="info-title">{{infoRow.activityName}}</div>
|
||||
<pdf-preview style="height: calc(100vh - 46px - 44px - 186px - 57px)" :content="infoRow.introduce"></pdf-preview>
|
||||
</div>
|
||||
|
||||
<van-button @click="onApply(infoRow)" type="primary" block>
|
||||
<span v-if="time >= 0">
|
||||
去报名
|
||||
</span>
|
||||
<template v-else>
|
||||
距离开始
|
||||
<van-count-down :time="Math.abs(time)" class="count-down" format="DD 天 HH 时 mm 分 ss 秒" @finish="time = 0"></van-count-down>
|
||||
</template>
|
||||
</van-button>
|
||||
</van-popup>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"pdf-preview": httpVueLoader("/components/plugins/sysFilePreview/PdfIndex.vue?v=" + new Date().getTime())
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
time: 0,
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
searchKeyword: '',
|
||||
year: new Date().getFullYear(),
|
||||
activityType: 2,
|
||||
},
|
||||
typeOptions: [
|
||||
{text: '全部', value: 1},
|
||||
{text: '即将开始', value: 4},
|
||||
{text: '报名中', value: 2},
|
||||
{text: '已结束', value: 3},
|
||||
],
|
||||
infoVisible: false,
|
||||
infoRow: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.infoRow = row
|
||||
this.time = this.$moment().diff(this.$moment(row.activitySignUpStartTime), 'milliseconds')
|
||||
this.infoVisible = true
|
||||
},
|
||||
onApply(row) {
|
||||
if(this.$moment().isBefore(this.$moment(row.activitySignUpStartTime))) {
|
||||
this.onView(row)
|
||||
return
|
||||
}
|
||||
this.$pjaxReplace('/platform/trainSingUp/apply/list/h5?id=' + row.id)
|
||||
},
|
||||
onReady() {
|
||||
this.doSearch()
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,89 @@
|
||||
const times = {
|
||||
template:
|
||||
/*language=HTML*/
|
||||
`
|
||||
<div>
|
||||
<van-action-sheet v-model="visible" title="时间段" cancel-text="取消">
|
||||
<button v-for="(item,index) in row?.courseTimes" type="button" class="van-action-sheet__item">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center">
|
||||
<div>
|
||||
<div class="van-action-sheet__name">
|
||||
<label>{{ weekdayCNMap[$moment(item.courseDate).day()] }}</label>
|
||||
<label>{{ $moment(item.courseDate).format('YYYY-MM-DD') }}</label>
|
||||
</div>
|
||||
<div class="van-action-sheet__subname">
|
||||
{{$moment(item.courseStartTime).format('MM-DD HH:mm') + ' 至 ' + $moment(item.courseEndTime).format('MM-DD HH:mm')}}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="row.isSign === true && row.isMobileSign === true" class="sign_button">
|
||||
<van-button v-if="item.isAttend !== true" @click.stop="onSign(item)" size="mini" type="info">签到</van-button>
|
||||
<van-button v-if="item.isAttend === true" size="mini" type="info" disabled>已签到</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</van-action-sheet>
|
||||
|
||||
<van-popup round :safe-area-inset-bottom="true"
|
||||
:close-on-click-overlay="false"
|
||||
v-model="signVisible"
|
||||
:style="{ width: '80%', height: '66%' }"
|
||||
get-container="#app"
|
||||
@close="onSignClose"
|
||||
closeable
|
||||
>
|
||||
<scan-code ref="scanCodeRef"></scan-code>
|
||||
</van-popup>
|
||||
</div>
|
||||
`,
|
||||
store,
|
||||
data() {
|
||||
return {
|
||||
visible:false,
|
||||
row: null,
|
||||
weekdayCNMap: {0: '周日', 1: '周一', 2: '周二', 3: '周三', 4: '周四', 5: '周五', 6: '周六'},
|
||||
|
||||
selectCourseTime: {},
|
||||
signVisible: false,
|
||||
}
|
||||
},
|
||||
components: {
|
||||
"scan-code": httpVueLoader("/components/plugins/sysScanCode/index.vue?v=" + new Date().getTime())
|
||||
},
|
||||
methods: {
|
||||
onSignClose() {
|
||||
this.$refs.scanCodeRef.closeScan()
|
||||
},
|
||||
onOpen(row) {
|
||||
this.row = row
|
||||
this.visible = true
|
||||
},
|
||||
onSign(courseTime) {
|
||||
this.selectCourseTime = courseTime
|
||||
if(this.row.signType === 1) {
|
||||
this.signVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.scanCodeRef.init()
|
||||
})
|
||||
}
|
||||
if(this.row.signType === 2) {
|
||||
this.makeCode()
|
||||
}
|
||||
if(this.row.signType === 3) {
|
||||
this.$toast('此签到模式正在升级中')
|
||||
}
|
||||
},
|
||||
makeCode() {
|
||||
const url = '/platform/trainSingUp/mine/passiveScan'
|
||||
const data = url + '?id=' + this.selectCourseTime.id
|
||||
console.log(data)
|
||||
const content = jrQrcode.getQrBase64(data)
|
||||
vant.ImagePreview([content])
|
||||
},
|
||||
onClose(){
|
||||
this.visible = false
|
||||
},
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
const applyForm = {
|
||||
template:
|
||||
/*language=HTML*/
|
||||
`
|
||||
<div>
|
||||
<van-popup v-model="visible" position="right" :style="{ width: '100%', height: '100%', 'background-color': '#F7F8FA' }">
|
||||
<van-nav-bar title="报名信息" left-text="返回" left-arrow @click-left="visible = false" fixed placeholder></van-nav-bar>
|
||||
<van-form ref="formRef" class="form-container">
|
||||
<van-cell-group title="活动信息" class="form-section">
|
||||
<van-field label="活动名称" readonly v-model="row.courseName"></van-field>
|
||||
<van-field label="校区" readonly v-model="row.campus"></van-field>
|
||||
<van-field label="活动地点" readonly v-model="row.courseLocation"></van-field>
|
||||
</van-cell-group>
|
||||
<van-cell-group title="基础信息" class="form-section">
|
||||
<van-field label="姓名" readonly v-model="formData.username"></van-field>
|
||||
<van-field label="工号" readonly v-model="formData.loginname"></van-field>
|
||||
<van-field label="所在单位" readonly v-model="formData.unitName"></van-field>
|
||||
<van-field label="所属工会" readonly v-model="formData.unionName"></van-field>
|
||||
<van-field label="性别" readonly v-model="formData.sex"></van-field>
|
||||
<template v-if="row.courseIsLimitApply">
|
||||
<van-field label="报名时段"
|
||||
required
|
||||
:rules="[{ required: true, message: '请选择报名时段' }]"
|
||||
readonly
|
||||
@click="showCoursePicker = true"
|
||||
placeholder="请选择报名时段"
|
||||
name="courseTimeName"
|
||||
v-model="formData.courseTimeName">
|
||||
</van-field>
|
||||
<van-popup v-model="showCoursePicker" position="bottom">
|
||||
<van-picker
|
||||
show-toolbar
|
||||
:columns="courseTimeSelectList"
|
||||
@confirm="onCourseConfirm"
|
||||
@cancel="showCoursePicker=false"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
</template>
|
||||
<train-dynamic-form v-model="dynamicColumnsData" ref="dynamicForm"></train-dynamic-form>
|
||||
</van-cell-group>
|
||||
|
||||
<div class="form-actions">
|
||||
<van-button @click="onSubmit" round type="info">提交</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
</van-popup>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
row: {},
|
||||
activity: {},
|
||||
dynamicColumnsData: [],
|
||||
visible: false,
|
||||
formData: {},
|
||||
showCoursePicker: false,
|
||||
courseTimeSelectList: [],
|
||||
}
|
||||
},
|
||||
components: {
|
||||
"train-dynamic-form": httpVueLoader("/components/module/trainSignUp/TrainDynamicForm.vue")
|
||||
},
|
||||
methods: {
|
||||
async onOpen(row, course) {
|
||||
this.row = row
|
||||
this.init(row, course)
|
||||
if(row.courseIsLimitApply) {
|
||||
await this.getCourseTimeSelectList(row)
|
||||
}
|
||||
this.visible = true
|
||||
},
|
||||
init(row, course) {
|
||||
this.$set(this.formData, 'username', this.$store.state.user.username)
|
||||
this.$set(this.formData, 'loginname', this.$store.state.user.loginname)
|
||||
this.$set(this.formData, 'unionName', this.$store.state.user.union.name)
|
||||
this.$set(this.formData, 'unitName', this.$store.state.user.unit.name)
|
||||
this.$set(this.formData, 'sex', this.$store.state.user.sex)
|
||||
this.$set(this.formData, 'activityId', row.activityId)
|
||||
this.$set(this.formData, 'courseId', row.id)
|
||||
|
||||
this.dynamicColumnsData = course ? course.trainMobileSignColumnList : []
|
||||
this.dynamicColumnsData.forEach((item) => {
|
||||
item.columnValue = this.$store.state.user[item.columnCode] || ""
|
||||
})
|
||||
},
|
||||
onCourseConfirm(val){
|
||||
this.formData.activityCourseId = val.value
|
||||
this.$set(this.formData, "activityCourseId", val.value)
|
||||
this.$set(this.formData, "courseTimeName", val.text.substring(0, 12))
|
||||
this.showCoursePicker = false
|
||||
},
|
||||
async getCourseTimeSelectList(o) {
|
||||
const resp = await this.$axios.post('/platform/trainSingUp/apply/getCourseTimeSelectList',{courseId: o.id})
|
||||
if (resp.code === 0) {
|
||||
this.courseTimeSelectList = resp.data
|
||||
} else {
|
||||
this.$toast.fail("获取时段信息失败,请联系管理员")
|
||||
}
|
||||
},
|
||||
async validateSignUp() {
|
||||
// 验证自定义表单
|
||||
await this.$refs.dynamicForm.$refs.form.validate()
|
||||
// 获取家属人数
|
||||
let familyCount = this.dynamicColumnsData.filter(o => o.columnCode === 'xdqsrs').reduce((sum, item) => {
|
||||
return sum + (Number(item.columnValue) || 0)
|
||||
}, 0)
|
||||
|
||||
const res = await this.$axios.post("/platform/trainSingUp/apply/validateSignUp", {
|
||||
courseId: this.formData.courseId,
|
||||
currentFamilyNumber: familyCount
|
||||
})
|
||||
return res.code === 0
|
||||
},
|
||||
async validateCourseTime() {
|
||||
const res = await this.$axios.post('/platform/trainSingUp/apply/validateSourceSignUp', {
|
||||
activityCourseId: this.formData.activityCourseId,
|
||||
courseId: this.row.id
|
||||
})
|
||||
return res.code === 0
|
||||
},
|
||||
async onSubmit() {
|
||||
if(!await this.validateSignUp()) return
|
||||
|
||||
this.$refs.formRef.validate().then(() => {
|
||||
this.$dialog.confirm({
|
||||
title: "提示",
|
||||
message: "您确定要提交吗?"
|
||||
}).then(async () => {
|
||||
if (this.row.courseIsLimitApply) {
|
||||
if(!await this.validateCourseTime()) return
|
||||
}
|
||||
|
||||
const mobileColumnsValue = this.dynamicColumnsData.map((v) => {
|
||||
return {
|
||||
columnName: v.columnName,
|
||||
columnValue: v.columnValue,
|
||||
columnCode: v.columnCode,
|
||||
columnFormType: v.columnFormType
|
||||
}
|
||||
})
|
||||
this.formData.mobileColumnsValue = JSON.stringify(mobileColumnsValue)
|
||||
this.$axios.post("/platform/trainSingUp/apply/doSignUp", this.formData).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$toast(res.msg)
|
||||
this.visible = false
|
||||
this.$emit('refresh')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
.primary-color {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.sign_button .van-button{
|
||||
width: 66px;
|
||||
height: 30px;
|
||||
font-size: 14px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app">
|
||||
<van-nav-bar title="活动报名" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<van-sticky offset-top="46px">
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
<van-dropdown-item v-model="pageForm.courseTypeId" :options="typeOptions" :multiple="false"
|
||||
@change="doSearch"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</van-sticky>
|
||||
|
||||
<table-list api="/platform/trainSingUp/apply/pageData"
|
||||
:page_form.sync="pageForm"
|
||||
ref="tableListRef"
|
||||
@ready="onReady"
|
||||
>
|
||||
<template #header="{index,row}">
|
||||
<div class="item-header">
|
||||
<div class="item-title">{{ row.courseName }}</div>
|
||||
<div v-html="calcSignUpCount(row)"></div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="类型">{{row.typeName}}</table-column>
|
||||
<table-column label="地点">{{row.courseLocation}}</table-column>
|
||||
<table-column label="联系人">{{row.courseInstructor}}</table-column>
|
||||
<table-column label="时间">
|
||||
<span v-if="row.courseTimes && row.courseTimes.length === 1">
|
||||
{{ $moment(row.courseTimes[0].courseStartTime).format('HH:mm') + '~' + $moment(row.courseTimes[0].courseEndTime).format('HH:mm') }}
|
||||
</span>
|
||||
<span v-else @click="onTime(row)" class="primary-color">点我查看</span>
|
||||
</table-column>
|
||||
<table-column v-if="row.introduce" label="详细信息">
|
||||
<span @click="introduceRow = row; introduceVisible = true" class="primary-color">点我查看</span>
|
||||
</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div v-if="activity.wechat && row.isSign" class="action-btn" @click="this.vant.ImagePreview([activity.wechat])">
|
||||
<i class="fa fa-wechat"></i>
|
||||
<span>微信群二维码</span>
|
||||
</div>
|
||||
<template v-if="$moment().isBefore($moment(activity.activitySignUpEndTime))">
|
||||
<div v-if="row.isSign === false" class="action-btn" @click="onApply(row)">
|
||||
<i class="fa fa-sign-in"></i>
|
||||
<span>我要报名</span>
|
||||
</div>
|
||||
<div v-if="row.isSign === true" class="action-btn delete" @click="onCancel(row)">
|
||||
<i class="fa fa-trash"></i>
|
||||
<span>取消报名</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-if="row.isSign === true && row.isMobileSign === true && $moment().isAfter($moment(activity.activitySignUpEndTime))"
|
||||
class="action-btn"
|
||||
@click="onTime(row)"
|
||||
>
|
||||
<i class="fa fa-sign-in"></i>
|
||||
<span>签到</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<van-popup v-model="introduceVisible" position="right" :style="{ width: '100%', height: '100%', 'background-color': '#F7F8FA' }">
|
||||
<van-nav-bar title="详细信息" left-text="返回" left-arrow @click-left="introduceVisible = false" fixed placeholder></van-nav-bar>
|
||||
<pdf-preview style="height: calc(100vh - 46px)" :content="introduceRow.introduce"></pdf-preview>
|
||||
</van-popup>
|
||||
|
||||
<times ref="timesRef"></times>
|
||||
<apply-form ref="formRef" @refresh="refresh"></apply-form>
|
||||
</div>
|
||||
|
||||
<script src="${base!}/assets/platform/plugins/jr-qrcode/jr-qrcode.js"></script>
|
||||
<script>
|
||||
<!--#include('../common/times.js'){}#-->
|
||||
<!--#include('applyForm.js'){}#-->
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
'times': times,
|
||||
'apply-form': applyForm,
|
||||
"pdf-preview": httpVueLoader("/components/plugins/sysFilePreview/PdfIndex.vue?v=" + new Date().getTime())
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
searchKeyword: '',
|
||||
year: new Date().getFullYear(),
|
||||
courseTypeId: null,
|
||||
activityId: GetQueryString('id'),
|
||||
dataType: GetQueryString('dataType'),
|
||||
},
|
||||
typeOptions: [],
|
||||
assortOptions: [],
|
||||
sourceTypeOptions: [],
|
||||
introduceVisible: false,
|
||||
|
||||
introduceRow: {},
|
||||
activity: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
refresh() {
|
||||
this.doSearch()
|
||||
},
|
||||
async onTime(row) {
|
||||
// 如果设置签到,并且也报名的话
|
||||
if(row.isMobileSign === true && row.isSign === true) {
|
||||
const res = await this.$axios.post('/platform/trainSingUp/mine/queryCourseSign', {
|
||||
courseId: row.id
|
||||
})
|
||||
row.courseTimes = res.data
|
||||
}
|
||||
this.$refs.timesRef.onOpen(row)
|
||||
},
|
||||
onApply(row) {
|
||||
const course = this.sourceTypeOptions.find((v) => v.id === row.courseType)
|
||||
this.$axios.post('/platform/trainSingUp/apply/validateSignUp', {
|
||||
courseId: row.id
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code !== 0) {
|
||||
vant.Dialog.alert({
|
||||
title: '提示',
|
||||
message: res.msg,
|
||||
confirmButtonColor: '#1867b0'
|
||||
})
|
||||
} else {
|
||||
let lave = row.coursePeopleNumber - (row.hasRegisterNum + row.courseReservedNumber)
|
||||
if(row.reserveMode === 2 && lave <= 0) {
|
||||
vant.Dialog.alert({
|
||||
title: '提示',
|
||||
message: '您当前的报名为候补报名状态',
|
||||
confirmButtonColor: '#1867b0'
|
||||
})
|
||||
}
|
||||
this.$refs.formRef.onOpen(row, course)
|
||||
}
|
||||
})
|
||||
},
|
||||
onCancel(row) {
|
||||
vant.Dialog.confirm({
|
||||
title: '温馨提示',
|
||||
message: "您确定要<span style='color: red'>取消【" + row.courseName + "】</span>吗?",
|
||||
confirmButtonColor: '#1867b0',
|
||||
}).then(async () => {
|
||||
const resp = await this.$axios.post('/platform/trainSingUp/apply/cancelSignUp', {
|
||||
activityId: row.activityId,
|
||||
courseId: row.id
|
||||
})
|
||||
this.$toast(resp.msg)
|
||||
if (resp.code === 0) {
|
||||
this.doSearch()
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
calcSignUpCount(row) {
|
||||
let lave = row.coursePeopleNumber - (row.hasRegisterNum + row.courseReservedNumber)
|
||||
if(row.reserveMode === 2) {
|
||||
let lave2 = row.waitingNum - row.hasWaitingNum
|
||||
return "<span style='color: red'>余" + lave +"</span>/" + row.coursePeopleNumber + "人"
|
||||
+ ",<span style='color: red'>候补余" + lave2 + "</span>/" + row.waitingNum + "人"
|
||||
} else {
|
||||
return "<span style='color: red'>余" + lave +"</span>/" + row.coursePeopleNumber + "人"
|
||||
}
|
||||
},
|
||||
async onReady() {
|
||||
const typeList = await this.getCourseTypeList()
|
||||
this.sourceTypeOptions = clone(typeList)
|
||||
this.typeOptions = [
|
||||
{
|
||||
text: "全部类型",
|
||||
value: null
|
||||
}
|
||||
].concat(typeList.map((v) => ({ text: v.typeName, value: v.id })))
|
||||
if (this.typeOptions.length > 0) {
|
||||
this.pageForm.type = this.typeOptions[0].value
|
||||
this.doSearch()
|
||||
}
|
||||
this.fetchActivity()
|
||||
},
|
||||
fetchActivity() {
|
||||
this.$axios.post('/platform/trainSingUp/manage/findOne', {id: this.pageForm.activityId})
|
||||
.then((res) => {
|
||||
this.activity = res.data
|
||||
})
|
||||
},
|
||||
async getCourseTypeList() {
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/type/getAllType")
|
||||
return resp.data
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,130 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
|
||||
<style scoped>
|
||||
.info-title {
|
||||
font-weight: bold;
|
||||
background-color: white;
|
||||
padding: 13px;
|
||||
box-shadow: 0 8px 12px #ebedf0;
|
||||
text-align: center !important;
|
||||
}
|
||||
.info-container {
|
||||
height: calc(100vh - 46px - 44px);
|
||||
min-height: calc(100vh - 46px - 44px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.info-img {
|
||||
display: block;
|
||||
}
|
||||
.van-count-down {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app">
|
||||
<van-nav-bar title="品牌活动-我的报名" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||
|
||||
<van-sticky offset-top="46px">
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.activityType" :options="typeOptions" :multiple="false"
|
||||
@change="doSearch"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</van-sticky>
|
||||
|
||||
<table-list api="/platform/trainSingUp/apply/activityPageData"
|
||||
:page_form.sync="pageForm"
|
||||
ref="tableListRef"
|
||||
title="activityName"
|
||||
img="cover"
|
||||
@ready="onReady"
|
||||
>
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="面向对象">{{row.activityGroupName}}</table-column>
|
||||
<table-column label="报名时间">
|
||||
{{$moment(row.activitySignUpStartTime).format('MM/DD HH:mm') + '~' + $moment(row.activitySignUpEndTime).format('MM/DD HH:mm')}}
|
||||
</table-column>
|
||||
<table-column label="活动时间">
|
||||
{{$moment(row.activityStartTime).format('MM/DD HH:mm') + '~' + $moment(row.activityEndTime).format('MM/DD HH:mm')}}
|
||||
</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<span>查看介绍</span>
|
||||
</div>
|
||||
<div class="action-btn" @click="onApply(row)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
|
||||
<van-popup v-model="infoVisible" position="right" :style="{ width: '100%', height: '100%' }">
|
||||
<van-nav-bar title="详细信息" left-text="返回" left-arrow @click-left="infoVisible = false" fixed placeholder></van-nav-bar>
|
||||
|
||||
<div class="info-container">
|
||||
<van-image class="info-img" height="186" width="100%" :src="infoRow.cover"></van-image>
|
||||
<div class="info-title">{{infoRow.activityName}}</div>
|
||||
<pdf-preview style="height: calc(100vh - 46px - 44px - 186px - 57px)" :content="infoRow.introduce"></pdf-preview>
|
||||
</div>
|
||||
|
||||
<van-button @click="onApply(infoRow)" type="primary" block>下一步</van-button>
|
||||
</van-popup>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
store,
|
||||
components: {
|
||||
"pdf-preview": httpVueLoader("/components/plugins/sysFilePreview/PdfIndex.vue?v=" + new Date().getTime())
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pageForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
searchKeyword: '',
|
||||
year: new Date().getFullYear(),
|
||||
activityType: 1,
|
||||
dataType: 'mine'
|
||||
},
|
||||
typeOptions: [
|
||||
{text: '全部', value: 1},
|
||||
{text: '报名中', value: 2},
|
||||
{text: '已结束', value: 3},
|
||||
],
|
||||
infoVisible: false,
|
||||
infoRow: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onView(row) {
|
||||
this.infoRow = row
|
||||
this.infoVisible = true
|
||||
},
|
||||
onApply(row) {
|
||||
this.$pjaxReplace('/platform/trainSingUp/apply/list/h5?id=' + row.id + '&dataType=mine')
|
||||
},
|
||||
onReady() {
|
||||
this.doSearch()
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -744,7 +744,7 @@ layout("/layouts/platform_h5.html"){
|
||||
this.pageData()
|
||||
},
|
||||
async getAllType() {
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/manage/type/getAllType", {})
|
||||
const resp = await this.$axios.post("/platform/trainSingUp/type/getAllType", {})
|
||||
this.allColumnsData = resp.data
|
||||
return resp.data
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user