diff --git a/src/main/resources/static/assets/mobile/img/activity/culture-empty.png b/src/main/resources/static/assets/mobile/img/activity/culture-empty.png new file mode 100644 index 0000000..7363ec6 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/activity/culture-empty.png differ diff --git a/src/main/resources/static/assets/mobile/img/activity/family-empty.png b/src/main/resources/static/assets/mobile/img/activity/family-empty.png new file mode 100644 index 0000000..0a6d35c Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/activity/family-empty.png differ diff --git a/src/main/resources/static/assets/mobile/img/activity/hero/brand-hero-v2.png b/src/main/resources/static/assets/mobile/img/activity/hero/brand-hero-v2.png new file mode 100644 index 0000000..cf56618 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/activity/hero/brand-hero-v2.png differ diff --git a/src/main/resources/static/assets/mobile/img/activity/hero/culture-hero-v3.png b/src/main/resources/static/assets/mobile/img/activity/hero/culture-hero-v3.png new file mode 100644 index 0000000..a9b3777 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/activity/hero/culture-hero-v3.png differ diff --git a/src/main/resources/static/assets/mobile/img/activity/hero/family-hero-v3.png b/src/main/resources/static/assets/mobile/img/activity/hero/family-hero-v3.png new file mode 100644 index 0000000..41b2d42 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/activity/hero/family-hero-v3.png differ diff --git a/src/main/resources/static/assets/mobile/img/activity/hero/sports-hero-v2.png b/src/main/resources/static/assets/mobile/img/activity/hero/sports-hero-v2.png new file mode 100644 index 0000000..1384656 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/activity/hero/sports-hero-v2.png differ diff --git a/src/main/resources/static/assets/mobile/img/activity/schedule-empty.png b/src/main/resources/static/assets/mobile/img/activity/schedule-empty.png new file mode 100644 index 0000000..c3a5a47 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/activity/schedule-empty.png differ diff --git a/src/main/resources/static/assets/mobile/img/activity/sports-empty.png b/src/main/resources/static/assets/mobile/img/activity/sports-empty.png new file mode 100644 index 0000000..dd556d0 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/activity/sports-empty.png differ diff --git a/src/main/resources/static/assets/mobile/img/benefit/welfare-empty.png b/src/main/resources/static/assets/mobile/img/benefit/welfare-empty.png new file mode 100644 index 0000000..dbe0c4f Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/benefit/welfare-empty.png differ diff --git a/src/main/resources/static/assets/mobile/img/benefit/welfare-selection-hero-v2.png b/src/main/resources/static/assets/mobile/img/benefit/welfare-selection-hero-v2.png new file mode 100644 index 0000000..d9fbe6f Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/benefit/welfare-selection-hero-v2.png differ diff --git a/src/main/resources/static/assets/mobile/img/club/club-approval-empty.png b/src/main/resources/static/assets/mobile/img/club/club-approval-empty.png new file mode 100644 index 0000000..e155240 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/club/club-approval-empty.png differ diff --git a/src/main/resources/static/assets/mobile/img/common/smart-union-loading-red.svg b/src/main/resources/static/assets/mobile/img/common/smart-union-loading-red.svg new file mode 100644 index 0000000..25c2a72 --- /dev/null +++ b/src/main/resources/static/assets/mobile/img/common/smart-union-loading-red.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/main/resources/static/assets/mobile/img/condolence/condolence-empty.png b/src/main/resources/static/assets/mobile/img/condolence/condolence-empty.png new file mode 100644 index 0000000..0dd3232 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/condolence/condolence-empty.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/delegate-card-holder.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/delegate-card-holder.png new file mode 100644 index 0000000..7044be3 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/delegate-card-holder.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/delegate-read-empty.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/delegate-read-empty.png new file mode 100644 index 0000000..f43bd51 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/delegate-read-empty.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/delegate-read-hero.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/delegate-read-hero.png new file mode 100644 index 0000000..ef9670d Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/delegate-read-hero.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-dais-gray.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-dais-gray.png new file mode 100644 index 0000000..d38f5de Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-dais-gray.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-dais-green.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-dais-green.png new file mode 100644 index 0000000..5a11745 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-dais-green.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-dais.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-dais.png new file mode 100644 index 0000000..a3104e0 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-dais.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-list-hero.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-list-hero.png new file mode 100644 index 0000000..ae210d3 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/meeting-list-hero.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-available.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-available.png new file mode 100644 index 0000000..e7a8468 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-available.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-disabled.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-disabled.png new file mode 100644 index 0000000..076d6d0 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-disabled.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-mine.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-mine.png new file mode 100644 index 0000000..be5c56e Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-mine.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-occupied.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-occupied.png new file mode 100644 index 0000000..3f36759 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-occupied.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-selected.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-selected.png new file mode 100644 index 0000000..25979f3 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-selected.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-status-icon.png b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-status-icon.png new file mode 100644 index 0000000..f23cf61 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-status-icon.png differ diff --git a/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-status-icon.svg b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-status-icon.svg new file mode 100644 index 0000000..bc20f7d --- /dev/null +++ b/src/main/resources/static/assets/mobile/img/democratic/teachercongress/seat-status-icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/main/resources/static/assets/mobile/img/difficultHelp/difficult-help-empty.png b/src/main/resources/static/assets/mobile/img/difficultHelp/difficult-help-empty.png new file mode 100644 index 0000000..7e7eeaa Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/difficultHelp/difficult-help-empty.png differ diff --git a/src/main/resources/static/assets/mobile/img/home/v4/app-center-empty-v4.png b/src/main/resources/static/assets/mobile/img/home/v4/app-center-empty-v4.png new file mode 100644 index 0000000..34375bf Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/home/v4/app-center-empty-v4.png differ diff --git a/src/main/resources/static/assets/mobile/img/home/v4/apps-guide-banner.png b/src/main/resources/static/assets/mobile/img/home/v4/apps-guide-banner.png new file mode 100644 index 0000000..15402a9 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/home/v4/apps-guide-banner.png differ diff --git a/src/main/resources/static/assets/mobile/img/home/v4/feature-activity-v5.png b/src/main/resources/static/assets/mobile/img/home/v4/feature-activity-v5.png new file mode 100644 index 0000000..9724d80 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/home/v4/feature-activity-v5.png differ diff --git a/src/main/resources/static/assets/mobile/img/home/v4/feature-activity.png b/src/main/resources/static/assets/mobile/img/home/v4/feature-activity.png new file mode 100644 index 0000000..fe5a8be Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/home/v4/feature-activity.png differ diff --git a/src/main/resources/static/assets/mobile/img/home/v4/feature-benefit-v5.png b/src/main/resources/static/assets/mobile/img/home/v4/feature-benefit-v5.png new file mode 100644 index 0000000..7098f63 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/home/v4/feature-benefit-v5.png differ diff --git a/src/main/resources/static/assets/mobile/img/home/v4/feature-inclusive-v8.png b/src/main/resources/static/assets/mobile/img/home/v4/feature-inclusive-v8.png new file mode 100644 index 0000000..3faed4d Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/home/v4/feature-inclusive-v8.png differ diff --git a/src/main/resources/static/assets/mobile/img/home/v4/feature-model-v5.png b/src/main/resources/static/assets/mobile/img/home/v4/feature-model-v5.png new file mode 100644 index 0000000..9299937 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/home/v4/feature-model-v5.png differ diff --git a/src/main/resources/static/assets/mobile/img/home/v4/hero-campus.png b/src/main/resources/static/assets/mobile/img/home/v4/hero-campus.png new file mode 100644 index 0000000..d93173b Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/home/v4/hero-campus.png differ diff --git a/src/main/resources/static/assets/mobile/img/proposal/proposal-empty.png b/src/main/resources/static/assets/mobile/img/proposal/proposal-empty.png new file mode 100644 index 0000000..f43bd51 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/proposal/proposal-empty.png differ diff --git a/src/main/resources/static/assets/mobile/img/unionReimburse/union-reimburse-empty.png b/src/main/resources/static/assets/mobile/img/unionReimburse/union-reimburse-empty.png new file mode 100644 index 0000000..a3231b2 Binary files /dev/null and b/src/main/resources/static/assets/mobile/img/unionReimburse/union-reimburse-empty.png differ diff --git a/src/main/resources/static/assets/platform/images/tour/tour-h5-empty-v3.png b/src/main/resources/static/assets/platform/images/tour/tour-h5-empty-v3.png new file mode 100644 index 0000000..8cb08ea Binary files /dev/null and b/src/main/resources/static/assets/platform/images/tour/tour-h5-empty-v3.png differ diff --git a/src/main/resources/static/assets/platform/images/tour/tour-h5-hero-v3.png b/src/main/resources/static/assets/platform/images/tour/tour-h5-hero-v3.png new file mode 100644 index 0000000..7af1bf7 Binary files /dev/null and b/src/main/resources/static/assets/platform/images/tour/tour-h5-hero-v3.png differ diff --git a/src/main/resources/static/assets/platform/plugins/panzoom/panzoom.min.js b/src/main/resources/static/assets/platform/plugins/panzoom/panzoom.min.js new file mode 100644 index 0000000..6bf074f --- /dev/null +++ b/src/main/resources/static/assets/platform/plugins/panzoom/panzoom.min.js @@ -0,0 +1,16 @@ +/** +* Panzoom 4.6.2 for panning and zooming elements using CSS transforms +* Copyright Timmy Willison and other contributors +* https://github.com/timmywil/panzoom/blob/main/MIT-License.txt +*/ +((e,t)=>{"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Panzoom=t()})(this,function(){"undefined"!=typeof window&&(window.NodeList&&!NodeList.prototype.forEach&&(NodeList.prototype.forEach=Array.prototype.forEach),"function"!=typeof window.CustomEvent)&&(window.CustomEvent=function(e,t){t=t||{bubbles:!1,cancelable:!1,detail:null};var n=document.createEvent("CustomEvent");return n.initCustomEvent(e,t.bubbles,t.cancelable,t.detail),n});let i="undefined"!=typeof document&&!!document.documentMode,a;let l=["webkit","moz","ms"],s={};function z(e){if(s[e])return s[e];var t=a=a||document.createElement("div").style;if(e in t)return s[e]=e;var n=e[0].toUpperCase()+e.slice(1);let o=l.length;for(;o--;){var r=""+l[o]+n;if(r in t)return s[e]=r}}function r(e,t){return parseFloat(t[z(e)])||0}function c(e,t,n=window.getComputedStyle(e)){var o="border"===t?"Width":"";return{left:r(t+"Left"+o,n),right:r(t+"Right"+o,n),top:r(t+"Top"+o,n),bottom:r(t+"Bottom"+o,n)}}function X(e,t,n){e.style[z(t)]=n}function Y(e){let t=e.parentNode;t&&1===t.nodeType||(t=document.documentElement);var n=window.getComputedStyle(e),o=window.getComputedStyle(t),r=e.getBoundingClientRect(),a=t.getBoundingClientRect();return{elem:{style:n,width:r.width,height:r.height,top:r.top,bottom:r.bottom,left:r.left,right:r.right,margin:c(e,"margin",n),border:c(e,"border",n)},parent:{style:o,width:a.width,height:a.height,top:a.top,bottom:a.bottom,left:a.left,right:a.right,padding:c(t,"padding",o),border:c(t,"border",o)}}}let C={down:"mousedown",move:"mousemove",up:"mouseup mouseleave"};function N(e,t,n,o){C[e].split(" ").forEach(e=>{t.addEventListener(e,n,o)})}function T(e,t,n){C[e].split(" ").forEach(e=>{t.removeEventListener(e,n)})}function $(e,t){let n=e.length;for(;n--;)if(e[n].pointerId===t.pointerId)return n;return-1}function L(e,t){let n;if(t.touches){n=0;for(var o of t.touches)o.pointerId=n++,L(e,o)}else-1<(n=$(e,t))&&e.splice(n,1),e.push(t)}function V(e){let t=(e=e.slice(0)).pop();for(var n;n=e.pop();)t={clientX:(n.clientX-t.clientX)/2+t.clientX,clientY:(n.clientY-t.clientY)/2+t.clientY};return t}function G(e){var t;return e.length<2?0:(t=e[0],e=e[1],Math.sqrt(Math.pow(Math.abs(e.clientX-t.clientX),2)+Math.pow(Math.abs(e.clientY-t.clientY),2)))}"undefined"!=typeof window&&("function"==typeof window.PointerEvent?C={down:"pointerdown",move:"pointermove",up:"pointerup pointerleave pointercancel"}:"function"==typeof window.TouchEvent&&(C={down:"touchstart",move:"touchmove",up:"touchend touchcancel"}));let I=/^http:[\w\.\/]+svg$/; +/** + * Panzoom for panning and zooming elements using CSS transforms + * https://github.com/timmywil/panzoom + * + * Copyright Timmy Willison and other contributors + * Released under the MIT license + * https://github.com/timmywil/panzoom/blob/main/MIT-License.txt + * + */ +let R={animate:!1,canvas:!1,cursor:"move",disablePan:!1,disableZoom:!1,disableXAxis:!1,disableYAxis:!1,duration:200,easing:"ease-in-out",exclude:[],excludeClass:"panzoom-exclude",handleStartEvent:e=>{e.preventDefault(),e.stopPropagation()},maxScale:4,minScale:.125,overflow:"hidden",panOnlyWhenZoomed:!1,pinchAndPan:!1,relative:!1,setTransform:function(e,{x:t,y:n,scale:o,isSVG:r},a){X(e,"transform",`scale(${o}) translate(${t}px, ${n}px)`),r&&i&&(o=window.getComputedStyle(e).getPropertyValue("transform"),e.setAttribute("transform",o))},startX:0,startY:0,startScale:1,step:.3,touchAction:"none"};function e(d,p){if(!d)throw new Error("Panzoom requires an element as an argument");if(1!==d.nodeType)throw new Error("Panzoom requires an element with a nodeType of 1");if(!(e=>{let t=e;for(;t&&t.parentNode;){if(t.parentNode===document)return 1;t=t.parentNode instanceof ShadowRoot?t.parentNode.host:t.parentNode}})(d))throw new Error("Panzoom should be called on elements that have been attached to the DOM");p=Object.assign(Object.assign({},R),p);e=d;let c=I.test(e.namespaceURI)&&"svg"!==e.nodeName.toLowerCase();var e;let n=d.parentNode;n.style.overflow=p.overflow,n.style.userSelect="none",n.style.touchAction=p.touchAction,(p.canvas?n:d).style.cursor=p.cursor,d.style.userSelect="none",d.style.touchAction=p.touchAction,X(d,"transformOrigin","string"==typeof p.origin?p.origin:c?"0 0":"50% 50%");let u=0,m=0,f=1,a=!1;function r(e,t,n){n.silent||(n=new CustomEvent(e,{detail:t}),d.dispatchEvent(n))}function l(t,n,e){let o={x:u,y:m,scale:f,isSVG:c,originalEvent:e};return requestAnimationFrame(()=>{var e;"boolean"==typeof n.animate&&(n.animate?(e=n,X(d,"transition",`${z("transform")} ${e.duration}ms `+e.easing)):X(d,"transition","none")),n.setTransform(d,o,n),r(t,o,n),r("panzoomchange",o,n)}),o}function s(e,t,n,o){var r,a,i,l,s=Object.assign(Object.assign({},p),o),c={x:u,y:m,opts:s};return(null!=o&&o.force||!(s.disablePan||s.panOnlyWhenZoomed&&f===s.startScale))&&(e=parseFloat(e),t=parseFloat(t),s.disableXAxis||(c.x=(s.relative?u:0)+e),s.disableYAxis||(c.y=(s.relative?m:0)+t),s.contain&&(e=((t=(e=(o=Y(d)).elem.width/f)*n)-e)/2,a=((r=(a=o.elem.height/f)*n)-a)/2,"inside"===s.contain?(i=(-o.elem.margin.left-o.parent.padding.left+e)/n,l=(o.parent.width-t-o.parent.padding.left-o.elem.margin.left-o.parent.border.left-o.parent.border.right+e)/n,c.x=Math.max(Math.min(c.x,l),i),l=(-o.elem.margin.top-o.parent.padding.top+a)/n,i=(o.parent.height-r-o.parent.padding.top-o.elem.margin.top-o.parent.border.top-o.parent.border.bottom+a)/n,c.y=Math.max(Math.min(c.y,i),l)):"outside"===s.contain&&(i=(-(t-o.parent.width)-o.parent.padding.left-o.parent.border.left-o.parent.border.right+e)/n,l=(e-o.parent.padding.left)/n,c.x=Math.max(Math.min(c.x,l),i),t=(-(r-o.parent.height)-o.parent.padding.top-o.parent.border.top-o.parent.border.bottom+a)/n,e=(a-o.parent.padding.top)/n,c.y=Math.max(Math.min(c.y,e),t))),s.roundPixels)&&(c.x=Math.round(c.x),c.y=Math.round(c.y)),c}function h(n,o){var r,a=Object.assign(Object.assign({},p),o),i={scale:f,opts:a};if(null!=o&&o.force||!a.disableZoom){let e=p.minScale,t=p.maxScale;a.contain&&(a=(o=Y(d)).elem.width/f,r=o.elem.height/f,1{i(p.startX,p.startY,{animate:!1,force:!0})});let y,b,w,x,O,E,S=[];function o(e){((t,n)=>{for(let e=t;null!=e;e=e.parentNode)if(o=e,r=n.excludeClass,1===o.nodeType&&-1<` ${o=o,(o.getAttribute("class")||"").trim()} `.indexOf(` ${r} `)||-1({x:u,y:m}),getScale:()=>f,getOptions:()=>{var e,t=p,n={};for(e in t)t.hasOwnProperty(e)&&(n[e]=t[e]);return n},handleDown:o,handleMove:M,handleUp:A,pan:i,reset:function(e){var e=Object.assign(Object.assign(Object.assign({},p),{animate:!0,force:!0}),e),t=(f=h(e.startScale,e).scale,s(e.startX,e.startY,f,e));return u=t.x,m=t.y,l("panzoomreset",e)},resetStyle:function(){n.style.overflow="",n.style.userSelect="",n.style.touchAction="",n.style.cursor="",d.style.cursor="",d.style.userSelect="",d.style.touchAction="",X(d,"transformOrigin","")},setOptions:function(e={}){for(var t in e)e.hasOwnProperty(t)&&(p[t]=e[t]);(e.hasOwnProperty("cursor")||e.hasOwnProperty("canvas"))&&(n.style.cursor=d.style.cursor="",(p.canvas?n:d).style.cursor=p.cursor),e.hasOwnProperty("overflow")&&(n.style.overflow=e.overflow),e.hasOwnProperty("touchAction")&&(n.style.touchAction=e.touchAction,d.style.touchAction=e.touchAction)},setStyle:(e,t)=>X(d,e,t),zoom:g,zoomIn:function(e){return t(!0,e)},zoomOut:function(e){return t(!1,e)},zoomToPoint:v,zoomWithWheel:function(e,t){e.preventDefault();var t=Object.assign(Object.assign(Object.assign({},p),t),{animate:!1}),n=(0===e.deltaY&&e.deltaX?e.deltaX:e.deltaY)<0?1:-1;return v(h(f*Math.exp(n*t.step/3),t).scale,e,t,e)}}}return e.defaultOptions=R,e}); \ No newline at end of file diff --git a/src/main/resources/static/components/module/activity/ActivityScheduleCalendar.vue b/src/main/resources/static/components/module/activity/ActivityScheduleCalendar.vue new file mode 100644 index 0000000..85d4021 --- /dev/null +++ b/src/main/resources/static/components/module/activity/ActivityScheduleCalendar.vue @@ -0,0 +1,634 @@ + + + + + diff --git a/src/main/resources/views/platform/zhghh5/club/common/clubUserJoin.css b/src/main/resources/views/platform/zhghh5/club/common/clubUserJoin.css new file mode 100644 index 0000000..38ea514 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/club/common/clubUserJoin.css @@ -0,0 +1,221 @@ +.club-user-join-popup { + overflow: hidden; + background: #f3f7fc; +} + +.club-user-join-detail { + display: flex; + height: 100%; + padding-top: 46px; + overflow: hidden; + box-sizing: border-box; + background: #f3f7fc; + color: #1f2d3d; + flex-direction: column; +} + +.club-user-join-detail > .van-nav-bar { + z-index: 20; + background: #fff; +} + +.club-user-join-detail > .van-nav-bar .van-icon, +.club-user-join-detail > .van-nav-bar .van-nav-bar__text { + color: #1989fa; +} + +.club-user-join-detail__scroll { + min-height: 0; + overflow-y: auto; + flex: 1; + -webkit-overflow-scrolling: touch; +} + +.club-user-join-detail__content { + padding: 12px 15px calc(18px + env(safe-area-inset-bottom)); +} + +.club-user-join-card { + margin-bottom: 11px; + overflow: hidden; + border: 1px solid #e9eff7; + border-radius: 10px; + background: #fff; + box-shadow: 0 3px 11px rgba(51, 87, 126, .08); +} + +.club-user-join-card__title { + position: relative; + margin: 0; + padding: 12px 14px 8px 21px; + color: #354255; + font-size: 15px; + font-weight: 600; + line-height: 22px; +} + +.club-user-join-card__title::before { + position: absolute; + top: 15px; + bottom: 11px; + left: 12px; + width: 2px; + border-radius: 2px; + background: #1989fa; + content: ''; +} + +.club-user-join-card__grid { + display: grid; + padding: 0 14px; + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.club-user-join-card__item { + min-width: 0; + padding: 0 10px 13px 0; +} + +.club-user-join-card__item--full { + grid-column: span 2; +} + +.club-user-join-card__item span, +.club-user-join-material > span { + display: block; + margin-bottom: 4px; + color: #8b9bb0; + font-size: 12px; +} + +.club-user-join-card__item strong { + display: block; + overflow: hidden; + color: #40526a; + font-size: 13px; + font-weight: 400; + line-height: 19px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.club-user-join-card__item--full strong { + white-space: normal; +} + +.club-user-join-material { + display: flex; + padding: 0 14px; + align-items: center; + min-height: 40px; + margin-bottom: 12px; +} + +.club-user-join-material > span { + flex: 0 0 82px; + margin: 0; +} + +.club-user-join-material strong { + color: #40526a; + font-size: 13px; + font-weight: 400; +} + +.club-user-join-material .van-image { + width: 56px; + height: 40px; + overflow: hidden; + border: 1px solid #edf2f8; + border-radius: 6px; +} + +.club-user-join-info-card .van-cell-group { + margin: 0; + background: transparent; +} + +.club-user-join-info-card .van-cell { + min-height: 44px; + padding: 10px 14px; + background: transparent; +} + +.club-user-join-info-card .van-cell:not(:last-child)::after { + right: 14px; + left: 14px; + border-color: #eef2f7; +} + +.club-user-join-info-card .van-cell__title { + width: 102px; + color: #596779; + font-size: 12px; + line-height: 24px; + flex: 0 0 102px; +} + +.club-user-join-info-card .van-cell__value { + min-width: 0; + color: #4f5d70; + font-size: 12px; + line-height: 24px; + text-align: left; + overflow-wrap: anywhere; +} + +.club-user-join-info-card .club-user-join-info-long-cell { + display: block; +} + +.club-user-join-info-card .club-user-join-info-long-cell .van-cell__title { + width: auto; + max-width: 100%; +} + +.club-user-join-info-card .club-user-join-info-long-cell .van-cell__value { + margin-top: 7px; +} + +.club-user-join-info-image { + display: block; + width: 56px; + height: 40px; + overflow: hidden; + border: 1px solid #edf2f8; + border-radius: 6px; +} + +.club-user-join-task-card .van-cell-group { + margin: 0; + background: transparent; +} + +.club-user-join-task-card .van-cell { + min-height: 44px; + padding: 10px 14px; + background: transparent; +} + +.club-user-join-task-card .van-cell:not(:last-child)::after { + right: 14px; + left: 14px; + border-color: #eef2f7; +} + +.club-user-join-task-card .van-cell__title { + width: 102px; + color: #596779; + font-size: 12px; + line-height: 24px; + flex: 0 0 102px; +} + +.club-user-join-task-card .van-cell__value { + min-width: 0; + color: #4f5d70; + font-size: 12px; + line-height: 24px; + text-align: left; + overflow-wrap: anywhere; +} diff --git a/src/main/resources/views/platform/zhghh5/dayofficework/tour/common/theme.css b/src/main/resources/views/platform/zhghh5/dayofficework/tour/common/theme.css new file mode 100644 index 0000000..84fec38 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/dayofficework/tour/common/theme.css @@ -0,0 +1,283 @@ +/* 疗休养移动端统一视觉主题:仅使用 tour-h5-theme 下的业务类,避免影响其他 H5 模块。 */ +body { + background-color: #f3f7fd; +} + +[v-cloak] { + display: none; +} + +.tour-h5-theme { + min-height: 100vh; + color: #263548; + background-color: #f3f7fd; + box-sizing: border-box; +} + +/* 页面接口首次加载时使用结构化骨架,避免先显示空字段或旧列表。 */ +.tour-content-skeleton { + padding: 12px; + background: #f3f7fd; + box-sizing: border-box; +} + +.tour-content-skeleton__cover, +.tour-content-skeleton__title, +.tour-content-skeleton__row, +.tour-content-skeleton__card { + background: linear-gradient(90deg, #edf2f8 25%, #f8fbff 37%, #edf2f8 63%); + background-size: 400% 100%; + animation: tour-content-skeleton-loading 1.35s ease infinite; +} + +.tour-content-skeleton__cover { height: 168px; border-radius: 14px; } +.tour-content-skeleton__title { width: 46%; height: 18px; margin: 16px 2px 10px; border-radius: 9px; } +.tour-content-skeleton__row { width: 76%; height: 13px; margin: 10px 2px; border-radius: 7px; } +.tour-content-skeleton__card { height: 126px; margin-top: 12px; border-radius: 14px; } + +@keyframes tour-content-skeleton-loading { + 0% { background-position: 100% 50%; } + 100% { background-position: 0 50%; } +} + +.tour-h5-theme .van-nav-bar { + background-color: #fff; +} + +.tour-h5-theme .van-nav-bar__title { + color: #172033; + font-size: 16px; + font-weight: 600; +} + +.tour-h5-theme .van-nav-bar .van-icon, +.tour-h5-theme .van-nav-bar__text { + color: #1989fa; +} + +.tour-h5-theme .van-nav-bar::after, +.tour-h5-theme .van-hairline--bottom::after { + border-bottom-color: #edf2f8; +} + +.tour-h5-card { + overflow: hidden; + border-radius: 12px; + background-color: #fff; + box-shadow: 0 7px 20px rgba(55, 85, 126, .08); +} + +.tour-h5-section-title { + position: relative; + display: flex; + min-height: 46px; + padding: 0 14px 0 20px; + align-items: center; + justify-content: space-between; + color: #202938; + font-size: 16px; + line-height: 22px; + font-weight: 600; + box-sizing: border-box; +} + +.tour-h5-section-title::before { + position: absolute; + top: 15px; + bottom: 15px; + left: 10px; + width: 3px; + border-radius: 2px; + background-color: #1989fa; + content: ""; +} + +.tour-h5-tag { + display: inline-flex; + min-height: 22px; + padding: 2px 8px; + align-items: center; + justify-content: center; + border-radius: 11px; + color: #1989fa; + background-color: #eaf4ff; + font-size: 11px; + line-height: 18px; + box-sizing: border-box; + white-space: nowrap; +} + +.tour-h5-tag.is-success { + color: #20a765; + background-color: #e9f8f0; +} + +.tour-h5-tag.is-warning { + color: #e98018; + background-color: #fff3e4; +} + +.tour-h5-tag.is-muted { + color: #7c899b; + background-color: #f0f2f5; +} + +.tour-h5-search { + margin: 0 0 8px; + padding: 0; + overflow: hidden; + border-radius: 12px; + background-color: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .1); +} + +.tour-h5-search .van-search__content { + height: 42px; + padding-left: 12px; + align-items: center; + border-radius: 12px; + background-color: #fff; +} + +.tour-h5-search .van-field__control { + color: #263548; + font-size: 14px; +} + +.tour-h5-search .van-field__control::placeholder { + color: #a7b0bf; +} + +.tour-h5-filter { + overflow: hidden; + border-radius: 10px; + background-color: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .08); +} + +.tour-h5-filter .van-dropdown-menu__bar, +.tour-h5-filter .van-dropdown-menu__item, +.tour-h5-filter .van-dropdown-menu__title { + height: 44px; +} + +.tour-h5-filter .van-dropdown-menu__bar { + box-shadow: none; +} + +.tour-h5-filter .van-dropdown-menu__title { + color: #66758a; + font-size: 14px; +} + +.tour-h5-filter .van-dropdown-menu__title--active, +.tour-h5-filter .van-dropdown-item__option--active, +.tour-h5-filter .van-dropdown-item__option--active .van-dropdown-item__icon { + color: #1989fa; +} + +.tour-h5-filter .van-dropdown-item__content { + width: calc(100% - 24px); + margin: 0 12px; + overflow: hidden; + border-radius: 0 0 12px 12px; + box-shadow: 0 10px 24px rgba(31, 65, 108, .14); +} + +.tour-h5-empty { + display: flex; + min-height: 290px; + padding: 40px 18px 32px; + align-items: center; + justify-content: center; + flex-direction: column; + box-sizing: border-box; + text-align: center; +} + +.tour-h5-empty img { + display: block; + width: 60%; + max-width: 190px; + height: auto; + object-fit: contain; +} + +.tour-h5-empty__title { + margin-top: 8px; + color: #50627a; + font-size: 15px; + line-height: 22px; + font-weight: 600; +} + +.tour-h5-empty__hint { + margin-top: 5px; + color: #9aa7b8; + font-size: 12px; + line-height: 18px; +} + +.tour-h5-fixed-bar { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 30; + display: flex; + gap: 10px; + padding: 10px 12px calc(10px + env(safe-area-inset-bottom)); + border-top: 1px solid #edf1f6; + background-color: rgba(255, 255, 255, .98); + box-shadow: 0 -6px 18px rgba(38, 66, 103, .08); + box-sizing: border-box; +} + +.tour-h5-fixed-bar .van-button { + height: 42px; + border-radius: 8px; + font-size: 15px; + font-weight: 600; +} + +.tour-h5-theme .van-cell { + min-height: 48px; + padding: 13px 14px; + color: #35445a; + font-size: 14px; +} + +.tour-h5-theme .van-cell__title { + color: #65748a; +} + +.tour-h5-theme .van-cell__value { + color: #263548; +} + +.tour-h5-theme .van-field__label { + color: #65748a; +} + +.tour-h5-theme .van-field__control { + color: #263548; +} + +.tour-h5-theme .van-button--info, +.tour-h5-theme .van-button--primary { + border-color: #0f7bf3; + background-color: #0f7bf3; +} + +.tour-h5-theme .van-button--plain.van-button--info { + color: #0f7bf3; + background-color: #fff; +} + +@media (max-width: 350px) { + .tour-h5-fixed-bar { + gap: 7px; + padding-right: 10px; + padding-left: 10px; + } +} diff --git a/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/common/unionReimburse.css b/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/common/unionReimburse.css new file mode 100644 index 0000000..1d73007 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/dayofficework/unionReimburse/common/unionReimburse.css @@ -0,0 +1,490 @@ +.union-reimburse-page { + min-height: 100vh; + padding-bottom: calc(24px + env(safe-area-inset-bottom)); + box-sizing: border-box; + background: #f3f7fd; + color: #40526a; +} + +.union-reimburse-page .van-nav-bar, +.union-reimburse-page .van-sticky--fixed { background: #fff; } + +.union-reimburse-page .van-nav-bar__title { + color: #172033; + font-size: 16px; + font-weight: 600; +} + +.union-reimburse-page .van-nav-bar .van-icon, +.union-reimburse-page .van-nav-bar .van-nav-bar__text { color: #1989fa; } + +.union-reimburse-sticky { + padding: 22px 12px 1px; + box-sizing: border-box; + background: #f3f7fd; +} + +.union-reimburse-search { + margin: 0 0 8px; + padding: 0; + overflow: hidden; + border-radius: 12px; + background: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .1); +} + +.union-reimburse-search .van-search__content { + height: 42px; + padding-left: 12px; + align-items: center; + border-radius: 12px; + background: #fff; +} + +.union-reimburse-search .van-field__control { color: #263548; font-size: 14px; } +.union-reimburse-search .van-field__control::placeholder { color: #a7b0bf; } + +.union-reimburse-filter { + margin-bottom: 8px; + overflow: hidden; + border-radius: 10px; + background: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .08); +} + +.union-reimburse-filter .van-dropdown-menu__bar { height: 44px; box-shadow: none; } +.union-reimburse-filter .van-dropdown-menu__item, +.union-reimburse-filter .van-dropdown-menu__title { height: 44px; } +.union-reimburse-filter .van-dropdown-menu__item { align-items: center; justify-content: center; } +.union-reimburse-filter .van-dropdown-menu__title { + display: inline-flex; + align-items: center; + color: #66758a; + font-size: 14px; + line-height: 20px; +} + +.union-reimburse-filter .van-dropdown-menu__title--active, +.union-reimburse-filter .van-dropdown-item__option--active, +.union-reimburse-filter .van-dropdown-item__option--active .van-dropdown-item__icon { color: #1989fa; } + +.union-reimburse-filter .van-dropdown-item__content { + width: calc(100% - 24px); + margin: 0 12px; + overflow: hidden; + box-sizing: border-box; + border-radius: 0 0 12px 12px; + box-shadow: 0 10px 24px rgba(31, 65, 108, .14); +} + +.union-reimburse-filter .van-dropdown-item__option { + display: flex; + min-height: 48px; + padding: 0 16px; + align-items: center; + color: #46566c; + font-size: 14px; +} + +.union-reimburse-list-content { padding: 0 12px; } +.union-reimburse-page .table-list-container { margin-top: 0; padding-bottom: 2px; } +.union-reimburse-page .table-list-container .table-list-item { + margin-bottom: 12px; + padding: 14px; + border: 1px solid #e9eff7; + border-radius: 12px; + box-shadow: 0 5px 16px rgba(43, 73, 112, .08); +} + +.union-reimburse-card-header { display: flex; margin-bottom: 8px; align-items: flex-start; justify-content: space-between; } +.union-reimburse-card-header__heading { min-width: 0; padding-right: 10px; flex: 1; } +.union-reimburse-card-header__title { + overflow: hidden; + color: #253247; + font-size: 15px; + font-weight: 600; + line-height: 22px; + text-overflow: ellipsis; + white-space: nowrap; +} +.union-reimburse-card-header__sub { margin-top: 1px; color: #9ba6b6; font-size: 12px; line-height: 18px; } +.union-reimburse-card-header__status { display: inline-flex; flex: none; } +.union-reimburse-card-header__status.van-tag, +.union-reimburse-card-header__status .van-tag { + min-height: 24px; + padding: 3px 9px; + border: 0; + border-radius: 12px; + box-sizing: border-box; + font-size: 12px; + line-height: 18px; +} +.union-reimburse-card-header__status--pending { color: #1989fa; background: #eaf4ff; } +/* 报销成功与社团审核页 ProcessInstanceStateEnum 的“已完成”保持一致。 */ +.union-reimburse-card-header__status--success { color: #67c23a; background: #f0f9eb; } +.union-reimburse-card-header__status--danger { color: #e35d5d; background: #fff0f0; } + +.union-reimburse-page .table-list-container .table-list-item .item-actions { + margin-top: 10px; + padding-top: 10px; + border-top-color: #edf1f6; +} +.union-reimburse-page .table-list-container .table-list-item .action-btn { + min-height: 28px; + padding: 4px 11px; + border-radius: 14px; + color: #1989fa; + background: #eaf4ff; + font-size: 12px; + line-height: 18px; +} +.union-reimburse-page .table-list-container .table-list-item .action-btn.delete { color: #f04444; background: #fff0f0; } +.union-reimburse-page .table-list-container .table-list-item .action-btn.review { color: #1989fa; background: #eaf4ff; } +.union-reimburse-page .table-list-container .table-list-item .action-btn .van-icon { margin-right: 5px; font-size: 13px; } +.union-reimburse-page .empty-state { padding: 0; } + +.union-reimburse-list-skeleton { padding: 0; } +.union-reimburse-skeleton-card { + margin-bottom: 12px; + padding: 14px; + border: 1px solid #e9eff7; + border-radius: 12px; + background: #fff; +} +.union-reimburse-skeleton-line { + height: 13px; + margin-bottom: 12px; + border-radius: 7px; + background: linear-gradient(90deg, #f2f3f5 25%, #e6e8eb 37%, #f2f3f5 63%); + background-size: 400% 100%; + animation: union-reimburse-skeleton-loading 1.4s ease infinite; +} +.union-reimburse-skeleton-line--title { width: 46%; height: 16px; } +.union-reimburse-skeleton-line--short { width: 60%; } + +.union-reimburse-empty { + display: flex; + min-height: 280px; + padding: 46px 18px 36px; + align-items: center; + justify-content: center; + box-sizing: border-box; + flex-direction: column; + text-align: center; +} +.union-reimburse-empty img { display: block; width: 86%; max-width: 290px; height: auto; object-fit: contain; } +.union-reimburse-empty__title { margin-top: 14px; color: #50627a; font-size: 15px; font-weight: 600; line-height: 22px; } +.union-reimburse-empty__hint { margin-top: 5px; color: #9aa7b8; font-size: 12px; line-height: 18px; } + +/* 申请页沿用社团申请的卡片层级,保留报销业务原有字段与交互。 */ +.union-reimburse-form { padding-bottom: 0; } +.union-reimburse-form .custom-nav { box-shadow: none; } +.union-reimburse-form .form-container { padding: 12px 15px calc(86px + env(safe-area-inset-bottom)); } +.union-reimburse-form .form-section { + margin: 0 0 11px; + overflow: hidden; + border: 1px solid #e9eff7; + border-radius: 10px; + background: #fff; + box-shadow: 0 3px 11px rgba(51, 87, 126, .08); +} + +.union-reimburse-form .form-section .van-cell-group__title, +.union-reimburse-form .payment-toolbar, +.union-reimburse-form .invoice-toolbar { + position: relative; + min-height: 42px; + margin: 0; + padding: 12px 14px 8px 21px; + box-sizing: border-box; + color: #354255; + font-size: 15px; + font-weight: 600; + line-height: 22px; + background: #fff; +} + +.union-reimburse-form .form-section__title { + position: relative; + min-height: 41px; + margin: 0; + padding: 13px 15px 8px 24px; + box-sizing: border-box; + color: #1f2d3d; + font-size: 14px; + font-weight: 600; + line-height: 20px; + background: #fff; +} + +.union-reimburse-form .form-section__title::before { + position: absolute; + top: 16px; + left: 15px; + width: 3px; + height: 14px; + border-radius: 2px; + background: #1989fa; + content: ''; +} + +.union-reimburse-form .form-section .van-cell-group__title::before, +.union-reimburse-form .payment-toolbar::before, +.union-reimburse-form .invoice-toolbar::before { + position: absolute; + top: 15px; + bottom: 11px; + left: 12px; + width: 2px; + border-radius: 2px; + background: #1989fa; + content: ''; +} + +.union-reimburse-form .form-section .van-cell { min-height: 46px; padding: 11px 15px; background: transparent; } +.union-reimburse-form .form-section .van-cell::after { right: 15px; left: 15px; border-color: #eef2f7; } +.union-reimburse-form .form-section .van-field__label { width: 105px; color: #596779; font-size: 13px; line-height: 24px; } +.union-reimburse-form .payment-detail-item .van-cell--required::before { left: 6px; color: #f06464; } +.union-reimburse-form .form-section .van-field__control { color: #40526a; font-size: 14px; line-height: 24px; } +.union-reimburse-form .form-section .van-field__control::placeholder { color: #a7b0bf; } +.union-reimburse-form .more-text { display: block; } +.union-reimburse-form .more-text .van-field__label { width: auto; margin-bottom: 7px; } +.union-reimburse-form .more-text .van-field__control { + min-height: 88px; + padding: 10px 12px; + box-sizing: border-box; + border: 1px solid #c9d5e5; + border-radius: 10px; + background: #f7f9fd; +} + +/* 附件上传区域与困难帮扶申请页保持一致,避免上传控件被文本域样式包裹。 */ +.union-reimburse-form .form-section .reimburse-upload-field .van-field__control { + min-height: 0; + padding: 0; + border: 0; + border-radius: 0; + background: transparent; +} + +.union-reimburse-form .payment-section, +.union-reimburse-form .invoice-section { padding: 0 0 14px; } +.union-reimburse-form .payment-toolbar, +.union-reimburse-form .invoice-toolbar { display: flex; align-items: center; justify-content: space-between; } +.union-reimburse-form .payment-toolbar .van-button, +.union-reimburse-form .invoice-toolbar .van-button { + height: 28px; + padding: 0 12px; + border: 0; + border-radius: 14px; + color: #1989fa; + background: #eaf4ff; +} +.union-reimburse-form .payment-detail-item, +.union-reimburse-form .invoice-detail-item { + margin: 8px 14px 0; + overflow: hidden; + border: 1px solid #e6ebf2; + border-radius: 10px; + background: #fff; + box-shadow: none; +} +.union-reimburse-form .invoice-detail-item { padding: 0; } +.union-reimburse-form .invoice-detail-title { + min-height: 38px; + padding: 0 12px; + box-sizing: border-box; + color: #40526a; + font-size: 14px; + font-weight: 600; + line-height: 22px; + background: #f7f9fd; + border-bottom: 1px solid #eef2f7; +} +.union-reimburse-form .invoice-detail-line { + margin: 0; + padding: 8px 12px 0; + color: #718096; + font-size: 13px; + line-height: 20px; + word-break: break-all; +} +.union-reimburse-form .invoice-detail-line:last-of-type { padding-bottom: 8px; } +.union-reimburse-form .invoice-detail-actions, +.union-reimburse-form .payment-detail-actions { + min-height: 28px; + margin-top: 8px; + padding: 9px 12px; + box-sizing: border-box; + border-top: 1px solid #eef2f7; + background: #fff; +} +.union-reimburse-form .invoice-detail-actions { justify-content: flex-end; gap: 6px; } +.union-reimburse-form .invoice-detail-actions .van-button, +.union-reimburse-form .payment-detail-actions .payment-delete-btn { + height: 28px; + min-width: 52px; + padding: 0 10px; + border: 0; + border-radius: 14px; + font-size: 12px; + line-height: 18px; +} +.union-reimburse-form .invoice-detail-actions .van-button--info, +.union-reimburse-form .invoice-detail-actions .van-button--primary { + color: #1989fa; + background: #eaf4ff; +} +.union-reimburse-form .invoice-detail-actions .van-button--danger, +.union-reimburse-form .payment-detail-actions .payment-delete-btn { + color: #f04444; + background: #fff0f0; +} +.union-reimburse-form .invoice-detail-actions .van-icon, +.union-reimburse-form .payment-detail-actions .payment-delete-btn .van-icon { + margin-right: 4px; + font-size: 13px; +} +.union-reimburse-form .payment-detail-item .van-cell { padding-right: 12px; padding-left: 12px; } +.union-reimburse-form .payment-detail-title { + min-height: 38px; + padding: 0 12px; + color: #40526a; + background: #f7f9fd; + border-bottom-color: #eef2f7; +} +.union-reimburse-form .invoice-tip { margin: 8px 14px 10px; border-color: #dce9f8; color: #718096; background: #f5f9ff; } +.union-reimburse-form .form-actions { + gap: 10px; + padding: 10px 15px calc(10px + env(safe-area-inset-bottom)); + box-shadow: 0 -2px 12px rgba(43, 73, 112, .09); +} +.union-reimburse-form .form-actions .van-button { height: 40px; border-radius: 8px; font-size: 14px; font-weight: 500; } +.union-reimburse-form .form-actions .van-button--primary { border-color: #1989fa; background: #1989fa; box-shadow: none; } +.union-reimburse-form .form-actions .van-button--info.van-button--plain { color: #1989fa; border-color: #1989fa; } + +/* 新增、编辑发票弹框与申请页共用卡片、字段和操作按钮视觉规范。 */ +.union-reimburse-form .invoice-popup { + overflow: hidden; + background: #f3f7fd; +} +.union-reimburse-form .invoice-popup .van-nav-bar { flex: none; box-shadow: 0 1px 6px rgba(43, 73, 112, .08); } +.union-reimburse-form .invoice-popup .van-nav-bar__title { color: #1f2d3d; font-size: 16px; font-weight: 600; } +.union-reimburse-form .invoice-popup-body { + padding: 12px 15px; + box-sizing: border-box; + background: #f3f7fd; +} +.union-reimburse-form .invoice-popup-card { + overflow: hidden; + border: 1px solid #e9eff7; + border-radius: 10px; + background: #fff; + box-shadow: 0 3px 11px rgba(51, 87, 126, .08); +} +.union-reimburse-form .invoice-popup-card .van-cell { min-height: 46px; padding: 11px 15px; background: transparent; } +.union-reimburse-form .invoice-popup-card .van-cell::after { right: 15px; left: 15px; border-color: #eef2f7; } +.union-reimburse-form .invoice-popup-card .van-field__label { width: 105px; color: #596779; font-size: 13px; line-height: 24px; } +.union-reimburse-form .invoice-popup-card .van-field__control { color: #40526a; font-size: 14px; line-height: 24px; } +.union-reimburse-form .invoice-popup-card .van-field__control::placeholder { color: #a7b0bf; } +.union-reimburse-form .invoice-popup-card .more-text { display: block; } +.union-reimburse-form .invoice-popup-card .more-text .van-field__label { width: auto; margin-bottom: 7px; } +.union-reimburse-form .invoice-popup-card .more-text .van-field__control { + min-height: 88px; + padding: 10px 12px; + box-sizing: border-box; + border: 1px solid #c9d5e5; + border-radius: 10px; + background: #f7f9fd; +} + +/* 发票文件只保留上传控件本身,移除报销文本域的边框、背景和内边距。 */ +.union-reimburse-form .invoice-popup-card .more-text.invoice-popup-file-field .van-field__control { + min-height: 0; + padding: 0; + border: 0; + border-radius: 0; + background: transparent; +} +.union-reimburse-form .invoice-popup-tip { + margin: 10px 0 0; + padding: 9px 11px; + border-color: #dce9f8; + color: #718096; + background: #f5f9ff; +} +.union-reimburse-form .invoice-popup-actions { + flex: none; + gap: 10px; + padding: 10px 15px calc(10px + env(safe-area-inset-bottom)); + box-shadow: 0 -2px 12px rgba(43, 73, 112, .09); +} +.union-reimburse-form .invoice-popup-actions .van-button { height: 40px; border-radius: 8px; font-size: 14px; font-weight: 500; } +.union-reimburse-form .invoice-popup-actions .van-button--primary { border-color: #1989fa; background: #1989fa; box-shadow: none; } +.union-reimburse-form .invoice-popup-actions .van-button--info.van-button--plain { color: #1989fa; border-color: #1989fa; background: #fff; } + +/* 审核卡片与社团审核保持相同的标题、必填标记和按钮规格。 */ +.union-reimburse-approval { padding: 0; background: #f3f7fd; } +.union-reimburse-approval-card { + margin: 0 0 11px; + overflow: hidden; + border: 1px solid #e9eff7; + border-radius: 10px; + background: #fff; + box-shadow: 0 3px 11px rgba(51, 87, 126, .08); +} +.union-reimburse-approval-card__title { + position: relative; + margin: 0; + padding: 12px 14px 8px 21px; + color: #354255; + font-size: 15px; + font-weight: 600; + line-height: 22px; +} +.union-reimburse-approval-card__title::before { + position: absolute; + top: 15px; + bottom: 11px; + left: 12px; + width: 2px; + border-radius: 2px; + background: #1989fa; + content: ''; +} +.union-reimburse-approval-field-label { + position: relative; + margin: 0; + padding: 10px 14px 6px; + color: #596779; + font-size: 12px; + line-height: 24px; +} +.union-reimburse-approval-required { position: absolute; left: 6px; color: #ee0a24; font-size: 12px; } +.union-reimburse-approval-card .van-field.union-reimburse-approval-field { + width: calc(100% - 28px); + margin: 0 14px 14px; + padding: 12px; + box-sizing: border-box; + border: 1px solid #c9d5e5; + border-radius: 10px; + background: #f7f9fd; +} +.union-reimburse-approval-card .van-field.union-reimburse-approval-field .van-field__control { + min-height: 150px; + color: #253247; + font-size: 12px; + line-height: 22px; +} +.union-reimburse-approval-card .van-field.union-reimburse-approval-field::after { display: none; } +.union-reimburse-approval-actions { + display: flex; + column-gap: 10px; + padding: 10px 12px calc(12px + env(safe-area-inset-bottom)); +} +.union-reimburse-approval-actions .van-button { height: 40px; border-radius: 14px; font-size: 14px; } + +@keyframes union-reimburse-skeleton-loading { + 0% { background-position: 100% 50%; } + 100% { background-position: 0 50%; } +} diff --git a/src/main/resources/views/platform/zhghh5/democratic/proposal/common/info.css b/src/main/resources/views/platform/zhghh5/democratic/proposal/common/info.css new file mode 100644 index 0000000..49d5671 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/democratic/proposal/common/info.css @@ -0,0 +1,534 @@ +.proposal-view-page { + --proposal-view-primary: #1677ee; + --proposal-view-text: #354255; + --proposal-view-muted: #8a97a8; + min-height: 100%; + padding-bottom: calc(20px + env(safe-area-inset-bottom)); + box-sizing: border-box; + color: var(--proposal-view-text); + background: #f3f7fc; +} + +/* 提案 H5 列表统一使用全屏 Popup 承载详情和办理表单。 */ +.proposal-full-popup { + width: 100%; + height: 100%; + overflow: hidden; + background: #f3f7fc; +} + +.proposal-full-popup__page { + display: flex; + height: 100%; + padding-top: 46px; + overflow: hidden; + box-sizing: border-box; + flex-direction: column; +} + +.proposal-full-popup__page > .van-nav-bar { + z-index: 20; + background: #ffffff; +} + +.proposal-full-popup__scroll { + min-height: 0; + overflow-y: auto; + flex: 1; + -webkit-overflow-scrolling: touch; +} + +.proposal-full-popup__scroll .proposal-view-main { + padding-top: 18px; +} + +.proposal-popup-form-actions { + display: flex; + padding: 10px 12px calc(12px + env(safe-area-inset-bottom)); + justify-content: space-between; + column-gap: 10px; +} + +/* 提案页面按需启用的圆角按钮与分页样式,不影响未声明对应 class 的组件。 */ +.proposal-soft-button, +.proposal-soft-pagination { + --proposal-soft-primary: #1989fa; +} + +/* 提案审核弹框的次要操作按钮统一使用柔和圆角,不包含阴影或漫反射效果。 */ +.proposal-rounded-button { + border-radius: 14px; +} + +.proposal-soft-pagination { + column-gap: 2px; +} + +.proposal-soft-button { + border-color: var(--proposal-soft-primary); + border-radius: 14px; + background-color: var(--proposal-soft-primary); +} + +/* 保持危险操作原有红色语义。 */ +.proposal-soft-button--danger { + border-color: #ff4d4f; + background-color: #ff4d4f; +} + +/* 保持退回类操作原有橙色语义。 */ +.proposal-soft-button--warning { + border-color: #ff976a; + background-color: #ff976a; +} + +/* 校工会预审核四个操作按钮与 PC 端 Element UI 的 primary、danger、info 配色保持一致。 */ +.proposal-pre-audit-actions .proposal-pre-audit-button--primary { + border-color: var(--color-primary); + background-color: var(--color-primary); +} + +.proposal-pre-audit-actions .proposal-pre-audit-button--danger { + border-color: #f56c6c; + background-color: #f56c6c; +} + +.proposal-pre-audit-actions .proposal-pre-audit-button--info { + border-color: #909399; + background-color: #909399; +} + +.proposal-soft-pagination .van-pagination__item { + color: var(--proposal-soft-primary); + background-color: #f8fbff; + border-radius: 12px; + transition: color 0.2s ease, background-color 0.2s ease; +} + +.proposal-soft-pagination .van-pagination__item::after { + border-color: rgba(25, 137, 250, 0.16); + border-radius: inherit; +} + +.proposal-soft-pagination .van-pagination__item--active, +.proposal-soft-pagination .van-pagination__item:not(.van-pagination__item--disabled):active { + color: #fff; + background-color: var(--proposal-soft-primary); +} + +.proposal-soft-pagination .van-pagination__item--disabled, +.proposal-soft-pagination .van-pagination__item--disabled:active { + color: #646566; + background-color: #f7f8fa; +} + +.proposal-action-icon { + margin-right: 6px; + font-size: 15px; +} + +.reply-unit-popup { + display: flex; + height: 100%; + flex-direction: column; +} + +.reply-unit-toolbar { + display: grid; + min-height: 48px; + border-bottom: 1px solid #eee; + grid-template-columns: 64px 1fr 64px; + align-items: center; +} + +.reply-unit-toolbar button { + height: 48px; + padding: 0; + color: #666; + font-size: 14px; + background: transparent; + border: 0; +} + +.reply-unit-toolbar button:last-child { + color: #1989fa; +} + +.reply-unit-toolbar-title { + color: #222; + font-size: 16px; + font-weight: 600; + text-align: center; +} + +.reply-unit-list { + overflow-y: auto; + flex: 1; + -webkit-overflow-scrolling: touch; +} + +.reply-unit-empty { + padding: 48px 16px; + color: #999; + font-size: 14px; + text-align: center; +} + +.transfer-dialog { + padding: 18px 16px 76px; + box-sizing: border-box; +} + +.proposal-info-card { + margin-bottom: 16px; + padding: 16px; + background: #fff; + border-radius: 10px; +} + +.proposal-info-card .info-item { + display: flex; + margin-bottom: 10px; + flex-direction: column; + row-gap: 4px; +} + +.proposal-info-card .info-item label { + color: #969799; + font-size: 12px; +} + +.proposal-full-popup__page > .button-group { + display: flex; + padding: 10px 16px calc(10px + env(safe-area-inset-bottom)); + background: #fff; + column-gap: 10px; +} + +.proposal-view-main { + position: relative; + z-index: 2; + padding: 12px 15px 0; +} + +.proposal-view-card { + margin-bottom: 11px; + overflow: hidden; + border: 1px solid #e9eff7; + border-radius: 10px; + background: #ffffff; + box-shadow: 0 3px 11px rgba(51, 87, 126, 0.08); +} + +.proposal-view-card__title { + position: relative; + margin: 0; + padding: 12px 14px 8px 21px; + color: #354255; + font-size: 15px; + font-weight: 600; + line-height: 22px; +} + +.proposal-view-card__title::before { + position: absolute; + top: 15px; + bottom: 11px; + left: 12px; + width: 2px; + border-radius: 2px; + background: var(--proposal-view-primary); + content: ""; +} + +/* 审核、附议、反馈及答复输入框统一复用提案查询 Card 的视觉规范。 */ +.proposal-audit-card__required { + margin-left: 4px; + color: #ee0a24; + font-size: 14px; +} + +.proposal-view-card .van-field.proposal-audit-field { + width: calc(100% - 28px); + margin: 0 14px 14px; + padding: 12px; + border: 1px solid #c9d5e5; + border-radius: 10px; + background-color: #f7f9fd; + box-sizing: border-box; +} + +.proposal-view-card .van-field.proposal-audit-field .van-field__control { + min-height: 150px; + color: #253247; + line-height: 22px; +} + +.proposal-view-card .van-field.proposal-audit-field .van-field__control::placeholder { + color: #9aa7b8; +} + +.proposal-view-card .van-field.proposal-audit-field .van-field__word-limit { + color: #718096; +} + +.proposal-view-card .van-field.proposal-audit-field::after { + display: none; +} + +.proposal-view-card .van-cell-group { + margin: 0; + background: transparent; +} + +.proposal-view-card .van-cell { + min-height: 44px; + padding: 10px 14px; + background: transparent; +} + +.proposal-view-card .van-cell:not(:last-child)::after { + right: 14px; + left: 14px; + border-color: #eef2f7; +} + +.proposal-view-card .van-cell__title { + flex: 0 0 92px; + width: 92px; + color: #354255; + font-size: 14px; + font-weight: 600; + line-height: 24px; +} + +/* 纵向字段中 flex-basis 会转为标题高度,需要取消横向字段使用的 92px 固定占位。 */ +.proposal-view-card .direction-column-field .van-cell__title { + flex: none; + width: auto; +} + +.proposal-view-card .van-cell__value { + min-width: 0; + color: #4f5d70; + font-size: 14px; + line-height: 24px; + text-align: left; + overflow-wrap: anywhere; +} + +.proposal-view-card .proposal-view-long-cell { + display: block; +} + +.proposal-view-card .proposal-view-long-cell .van-cell__title { + width: auto; + max-width: 100%; +} + +.proposal-view-card .proposal-view-long-cell .van-cell__value { + margin-top: 7px; +} + +.proposal-view-rich-value, +.proposal-view-rich-value * { + max-width: 100%; + white-space: normal; + word-break: break-word; +} + +.proposal-view-rich-value img, +.proposal-view-rich-value image { + height: auto; + max-width: 100%; +} + +.proposal-view-card .van-tag { + font-size: 14px; + line-height: 18px; + white-space: normal; +} + +.proposal-view-merge-cell .van-cell__title { + flex: 1; + width: auto; +} + +.proposal-view-merge-cell .van-cell__label { + margin-top: 4px; + color: var(--proposal-view-muted); + font-size: 13px; + line-height: 20px; + white-space: normal; +} + +.proposal-flow-card__header { + display: flex; + align-items: center; + justify-content: space-between; +} + +.proposal-flow-card__hint { + display: inline-flex; + align-items: center; + padding-right: 14px; + color: var(--proposal-view-muted); + font-size: 13px; + line-height: 22px; + white-space: nowrap; +} + +.proposal-flow-card__hint .van-icon { + margin-left: 4px; + color: #7f8da0; + font-size: 17px; +} + +.proposal-flow-scroll { + width: 100%; + padding: 4px 14px 15px; + overflow-x: auto; + box-sizing: border-box; + scroll-behavior: smooth; + scroll-snap-type: x proximity; + scrollbar-width: none; + -webkit-overflow-scrolling: touch; +} + +.proposal-flow-scroll::-webkit-scrollbar { + display: none; +} + +.proposal-flow-track { + position: relative; + display: flex; + width: max-content; + min-width: 100%; + padding-top: 5px; +} + +.proposal-flow-track::before { + position: absolute; + top: 24px; + right: 52px; + left: 52px; + height: 2px; + background: #d8e9ff; + content: ""; +} + +.proposal-flow-node { + position: relative; + z-index: 1; + display: flex; + flex: 0 0 108px; + width: 108px; + padding: 0 6px; + border: 0; + outline: none; + box-sizing: border-box; + align-items: center; + flex-direction: column; + color: var(--proposal-view-text); + background: transparent; + font-family: inherit; + scroll-snap-align: center; + -webkit-tap-highlight-color: transparent; +} + +.proposal-flow-node__icon { + display: flex; + width: 38px; + height: 38px; + border: 3px solid #ffffff; + border-radius: 50%; + box-sizing: border-box; + align-items: center; + justify-content: center; + color: #ffffff; + background: var(--proposal-view-primary); + box-shadow: 0 2px 7px rgba(22, 119, 238, 0.22); + transition: box-shadow 0.2s ease, transform 0.2s ease; +} + +.proposal-flow-node__icon .van-icon { + font-size: 20px; +} + +.proposal-flow-node__title { + display: -webkit-box; + min-height: 40px; + margin-top: 8px; + overflow: hidden; + color: #354255; + font-size: 14px; + font-weight: 600; + line-height: 20px; + text-align: center; + word-break: break-word; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +.proposal-flow-node__handler { + display: block; + width: 100%; + margin-top: 1px; + overflow: hidden; + color: var(--proposal-view-muted); + font-size: 13px; + line-height: 20px; + text-align: center; + text-overflow: ellipsis; + white-space: nowrap; +} + +.proposal-flow-node.is-active .proposal-flow-node__icon { + box-shadow: 0 0 0 5px #e7f2ff, 0 3px 9px rgba(22, 119, 238, 0.28); + transform: scale(1.06); +} + +.proposal-flow-node.is-active .proposal-flow-node__title { + color: var(--proposal-view-primary); +} + +.proposal-flow-detail__name { + margin: 0; + padding: 4px 14px 10px; + border-bottom: 1px solid #eef2f7; + color: #26364a; + font-size: 16px; + font-weight: 600; + line-height: 24px; +} + +.proposal-flow-detail__tip { + padding: 9px 14px 12px; + border-top: 1px solid #eef2f7; + color: var(--proposal-view-muted); + font-size: 13px; + line-height: 20px; + text-align: center; +} + +.proposal-view-table-wrap { + width: 100%; + overflow-x: auto; +} + +.proposal-view-table-wrap .el-table { + min-width: 560px; + font-size: 14px; +} + +.proposal-view-slot:empty { + display: none; +} + +@media (min-width: 600px) { + .proposal-view-main { + max-width: 520px; + margin-right: auto; + margin-left: auto; + } +} diff --git a/src/main/resources/views/platform/zhghh5/democratic/proposal/common/task-popup.js b/src/main/resources/views/platform/zhghh5/democratic/proposal/common/task-popup.js new file mode 100644 index 0000000..bca0c02 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/democratic/proposal/common/task-popup.js @@ -0,0 +1,457 @@ +const PROPOSAL_TASK_POPUP = { + template: /*language=HTML*/ ` + +
+ +
+ +
+ + + + + + + +
+ 同意 + + 不同意 + + 退回 + +
+
+ 同意 + + 不同意 + + 退回(不审核) + + 退回(审核) + + + +
+
+ 同意答复 + + 退回答复 + +
+
+ 提交 + + 返回 + +
+
+
+
+
+ + + + + + + + + + + + + + +
+
+ +
选择答复单位
+ +
+
+ + + + + +
+
暂无可选办理单位
+
+
+ +
+ `, + dicts: ["PROPOSAL_FEEDBACK", "UNDERTAKE_SUGGESTION", "PROPOSAL_REPLY_IMPLEMENT"], + components: {"proposal-info": PROPOSAL_INFO}, + props: {kind: {type: String, required: true}, pageKey: {type: String, required: true}}, + data() { + return { + visible: false, + bizId: "", + action: "view", + formData: {}, + formLoading: false, + pendingSubmitType: 1, + feedbackPickerVisible: false, + resultPickerVisible: false, + implementPickerVisible: false, + candidatePickerVisible: false, + replyUnitPickerVisible: false, + confirmVisible: false, + supportCandidate: false, + candidates: [], + replyUnitOptions: [], + pendingReplyUnitIds: [], + unsubscribeHistoryLayer: null + } + }, + computed: { + isApproval() { + return this.action === "approval" + }, + title() { + const titles = { + delegation: "团长审核", + preAudit: "校工会预审核", + schoolLeaderApproval: "分管校领导审批", + feedbackEvaluation: "反馈评价", + suggestion: "承办单位意见", + unitReply: "承办单位答复", + caseCheck: "提案委员会审查" + }; + return this.isApproval ? titles[this.kind] : "提案详情" + }, + selectedReplyUnitNames() { + const ids = this.formData.tf_secondReplyUnitIds || []; + return this.replyUnitOptions.filter((item) => ids.indexOf(item.unitId) > -1).map((item) => item.unitName + "(" + (item.isMaster ? "主办" : "协办") + ")").join("、") + } + }, + methods: { + syncLayers(stack) { + this.$set(this, "visible", stack.includes("detail")); + this.$set(this, "feedbackPickerVisible", stack.includes("feedback-picker")); + this.$set(this, "resultPickerVisible", stack.includes("result-picker")); + this.$set(this, "implementPickerVisible", stack.includes("implement-picker")); + this.$set(this, "candidatePickerVisible", stack.includes("candidate-picker")); + this.$set(this, "replyUnitPickerVisible", stack.includes("reply-unit-picker")); + this.$set(this, "confirmVisible", stack.includes("submit-confirm")) + }, + openLayer(name) { + window.h5HistoryLayerManager.open(name) + }, closeLayer(name, callback) { + window.h5HistoryLayerManager.close(name, callback) + }, close() { + this.closeLayer("detail") + }, + /** row 提供详情主键和当前 WF 任务参数,action 为 view 或 approval。 */ + open(row, action) { + const defaultTaskNames = { + delegation: "团长审核", + preAudit: "校工会预审核", + feedbackEvaluation: "反馈评价", + unitReply: "承办单位答复", + caseCheck: "提案委员会审查" + } + const taskName = this.kind === "unitReply" ? (row.taskName || defaultTaskNames[this.kind]) : (row.curTaskName || row.taskName || defaultTaskNames[this.kind] || "") + this.$set(this, "bizId", row.id); + this.$set(this, "action", action); + this.$set(this, "formData", { + proposalId: row.id, + processTaskId: row.taskId || "", + taskKey: row.taskKey || "", + taskName: taskName, + instanceId: row.instanceId || "", + underTakeName: row.underTakeName || "", + underTakeIsMaster: !!row.underTakeIsMaster, + tf_opinion: "", + opinion: "" + }) + if (action === "approval" && this.kind === "unitReply") { + // 承办单位答复附件上传入口暂时停用,保留初始化代码便于后续恢复。 + // this.$set(this.formData, "tf_attachment", []) + this.loadCandidates(row.taskId || "") + } + if (action === "approval" && this.kind === "caseCheck") { + this.$set(this.formData, "tf_auditTime", moment().format("YYYY-MM-DD")); + this.$set(this.formData, "tf_username", (this.$store.state.user && this.$store.state.user.username) || ""); + this.$set(this.formData, "tf_caseCheckNeedSecondReply", 0); + this.$set(this.formData, "tf_secondReplyUnitIds", []); + this.loadReplyUnits(row.id) + } + this.openLayer("detail") + }, + loadCandidates(taskId) { + this.$axios.post("/flow/common/candidate", {taskId: taskId}).then((res) => { + if (res.code === 0) { + this.$set(this, "candidates", res.data.candidates || []); + this.$set(this, "supportCandidate", res.data.support) + } + }) + }, + confirmFeedback(value) { + this.$set(this.formData, "tf_feedback_name", value.text); + this.$set(this.formData, "tf_feedback", value.value); + this.closeLayer("feedback-picker") + }, + confirmResult(value) { + this.$set(this.formData, "result", value); + this.closeLayer("result-picker") + }, + confirmImplement(value) { + this.$set(this.formData, "tf_implementStateName", value.text); + this.$set(this.formData, "tf_implementState", value.value); + this.closeLayer("implement-picker") + }, + confirmCandidate(value) { + this.$set(this.formData, "tf_nextNodeOperatorName", value.text); + this.$set(this.formData, "tf_nextNodeOperator", value.value); + this.closeLayer("candidate-picker") + }, + validateSecondReply(value) { + return value === 0 || value === 1 + }, + validateSecondReplyUnits() { + return this.formData.tf_caseCheckNeedSecondReply !== 1 || (this.formData.tf_secondReplyUnitIds || []).length > 0 + }, + onSecondReplyChange(value) { + if (value !== 1) this.$set(this.formData, "tf_secondReplyUnitIds", []) + }, + loadReplyUnits(proposalId) { + this.$axios.post("/platform/proposal/case/check/listReplyUnits", {proposalId: proposalId}).then((res) => { + if (res && res.code === 0) this.$set(this, "replyUnitOptions", res.data || []) + }) + }, + openReplyUnitPicker() { + this.$set(this, "pendingReplyUnitIds", [...(this.formData.tf_secondReplyUnitIds || [])]); + this.openLayer("reply-unit-picker") + }, + toggleReplyUnit(item) { + const ids = [...this.pendingReplyUnitIds]; + const index = ids.indexOf(item.unitId); + if (index > -1) ids.splice(index, 1); else ids.push(item.unitId); + this.$set(this, "pendingReplyUnitIds", ids) + }, + confirmReplyUnits() { + this.$set(this.formData, "tf_secondReplyUnitIds", [...this.pendingReplyUnitIds]); + this.closeLayer("reply-unit-picker") + }, + buildCaseCheckData() { + const data = {...this.formData}; + const units = data.tf_caseCheckNeedSecondReply === 1 ? this.replyUnitOptions.filter((item) => data.tf_secondReplyUnitIds.indexOf(item.unitId) > -1) : []; + const masters = units.filter((item) => item.isMaster); + const slaves = units.filter((item) => !item.isMaster); + data.tf_masterUnitIds = masters.map((item) => item.unitId); + data.tf_masterUnitId = data.tf_masterUnitIds[0] || ""; + data.tf_masterUnitNames = masters.map((item) => item.unitName); + data.tf_masterUnitName = data.tf_masterUnitNames[0] || ""; + data.tf_masterUnitNameStr = data.tf_masterUnitNames.join(","); + data.tf_slaveUnitIds = slaves.map((item) => item.unitId); + data.tf_slaveUnitNames = slaves.map((item) => item.unitName); + data.tf_slaveUnitNameStr = data.tf_slaveUnitNames.join(","); + return data + }, + prepareSubmit(value) { + // 各办理页面提交前统一校验意见字段;空白字符按未填写处理,提示后不再打开确认弹框。 + const opinionConfig = this.kind === "suggestion" + ? {field: "opinion", message: "请输入反馈意见"} + : this.kind === "unitReply" + ? {field: "tf_opinion", message: "请填写答复内容"} + : {field: "tf_opinion", message: "请填写审批意见"} + if (!(this.formData[opinionConfig.field] || "").trim()) { + this.$toast(opinionConfig.message) + return + } + this.$refs.formRef.validate().then(() => { + this.$set(this, "pendingSubmitType", value); + this.openLayer("submit-confirm") + }).catch(() => { + }) + }, + /** 根据页面类型保留原接口和参数分支,成功后清理全部弹层历史并通知列表刷新。 */ + submit() { + this.$set(this, "formLoading", true) + let request + if (this.kind === "suggestion") request = this.$axios.post("/platform/proposal/suggestion/suggest", this.formData) + else if (this.kind === "schoolLeaderApproval") { + const data = {...this.formData, tf_approval: this.pendingSubmitType}; + delete data.taskKey; + delete data.taskName; + request = this.$axios.post("/platform/proposal/schoolLeaderApproval/executeTask", {data: JSON.stringify(data)}) + } else { + const data = this.kind === "caseCheck" ? { + ...this.buildCaseCheckData(), + submitType: this.pendingSubmitType + } : {...this.formData, submitType: this.pendingSubmitType} + if (this.kind === "preAudit") { + data.taskName = "startTask"; + if (this.pendingSubmitType === 4) { + data.tf_sourceTaskKey = this.formData.taskKey; + data.tf_audit = false + } + } + if (this.kind === "unitReply") { + delete data.underTakeIsMaster; + delete data.underTakeName + } + if (this.kind === "feedbackEvaluation" && data.tf_feedback === "DISSATISFIED") request = this.$axios.post("/platform/proposal/feedbackEvaluation/caseInfo", {instId: data.instanceId}).then((res) => { + if (res.code !== 0) return Promise.reject(new Error(res.msg || "查询立案信息失败")); + data.tf_masterUnitId = res.data.tf_masterUnitId; + return this.$axios.post("/flow/common/executeTask", {data: JSON.stringify(data)}) + }) + else request = this.$axios.post("/flow/common/executeTask", {data: JSON.stringify(data)}) + } + request.then((res) => { + if (res && res.code === 0) { + this.$toast.success(res.msg); + window.h5HistoryLayerManager.closeAll(() => this.$emit("success")) + } + }).catch((error) => { + if (error && error.message && error.message !== "cancel") this.$toast.fail(error.message) + }).finally(() => { + this.$set(this, "formLoading", false) + }) + } + }, + created() { + window.h5HistoryLayerManager.ensureRegistered(this.pageKey); + this.$set(this, "unsubscribeHistoryLayer", window.h5HistoryLayerManager.subscribe((stack) => this.syncLayers(stack))) + }, + beforeDestroy() { + if (this.unsubscribeHistoryLayer) this.unsubscribeHistoryLayer(); + if (window.h5HistoryLayerManager.pageKey === this.pageKey) window.h5HistoryLayerManager.unregister(this.pageKey) + } +} diff --git a/src/main/resources/views/platform/zhghh5/democratic/proposal/transact/theme.css b/src/main/resources/views/platform/zhghh5/democratic/proposal/transact/theme.css new file mode 100644 index 0000000..1bc0841 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/democratic/proposal/transact/theme.css @@ -0,0 +1,17 @@ +/* 提案办理页统一使用 #1989fa 品牌蓝,并覆盖动态弹框及 Vant 组件继承的全局主题色。 */ +:root { + --color-primary: #1989fa; +} + +/* 公共提案详情组件拥有独立主题变量,需要在办理页内同步覆盖。 */ +.proposal-view { + --proposal-view-primary: #1989fa; +} + +.proposal-flow-node__icon { + box-shadow: 0 2px 7px rgba(25, 137, 250, 0.22); +} + +.proposal-flow-node.is-active .proposal-flow-node__icon { + box-shadow: 0 0 0 5px #e7f2ff, 0 3px 9px rgba(25, 137, 250, 0.28); +} diff --git a/src/main/resources/views/platform/zhghh5/staffbenefit/condolence/common/info.css b/src/main/resources/views/platform/zhghh5/staffbenefit/condolence/common/info.css new file mode 100644 index 0000000..3094ede --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/staffbenefit/condolence/common/info.css @@ -0,0 +1,176 @@ +.condolence-full-popup { + --color-primary: #1989fa; + width: 100%; + height: 100%; + overflow: hidden; + background: #f3f7fc; +} + +.condolence-full-popup__page { + display: flex; + height: 100%; + padding-top: 46px; + overflow: hidden; + box-sizing: border-box; + flex-direction: column; +} + +.condolence-full-popup__page > .van-nav-bar { + z-index: 20; + background: #fff; +} + +.condolence-full-popup__page > .van-nav-bar .van-icon, +.condolence-full-popup__page > .van-nav-bar .van-nav-bar__text { + color: #1989fa; +} + +.condolence-full-popup__scroll { + min-height: 0; + overflow-y: auto; + flex: 1; + -webkit-overflow-scrolling: touch; +} + +.condolence-info-main { + padding: 12px 15px calc(18px + env(safe-area-inset-bottom)); +} + +.condolence-info-card { + margin-bottom: 11px; + overflow: hidden; + border: 1px solid #e9eff7; + border-radius: 10px; + background: #fff; + box-shadow: 0 3px 11px rgba(51, 87, 126, .08); +} + +.condolence-info-card__title { + position: relative; + margin: 0; + padding: 12px 14px 8px 21px; + color: #354255; + font-size: 15px; + font-weight: 600; + line-height: 22px; +} + +.condolence-info-card__title::before { + position: absolute; + top: 15px; + bottom: 11px; + left: 12px; + width: 2px; + border-radius: 2px; + background: #1989fa; + content: ""; +} + +/* 审核意见复用详情 Card 标题,并与提案 delegation 审核输入区保持一致。 */ +.condolence-audit-card__required { + margin-left: 4px; + color: #ee0a24; + font-size: 14px; +} + +.condolence-info-card .van-field.condolence-audit-field { + width: calc(100% - 28px); + margin: 0 14px 14px; + padding: 12px; + box-sizing: border-box; + border: 1px solid #c9d5e5; + border-radius: 10px; + background: #f7f9fd; +} + +.condolence-info-card .van-field.condolence-audit-field .van-field__control { + min-height: 150px; + color: #253247; + line-height: 22px; +} + +.condolence-info-card .van-field.condolence-audit-field .van-field__control::placeholder { + color: #9aa7b8; +} + +.condolence-info-card .van-field.condolence-audit-field .van-field__word-limit { + color: #718096; +} + +.condolence-info-card .van-field.condolence-audit-field::after { + display: none; +} + +.condolence-popup-actions { + display: flex; + padding: 10px 12px calc(12px + env(safe-area-inset-bottom)); + justify-content: space-between; + column-gap: 10px; + background: transparent; +} + +.condolence-popup-actions .van-button { + border-radius: 14px; +} + +.condolence-popup-actions .condolence-action-primary { + border-color: #1989fa; + background: #1989fa; +} + +.condolence-popup-actions .condolence-action-danger { + border-color: #ff4d4f; + background: #ff4d4f; +} + +.condolence-info-card .van-cell-group { + margin: 0; + background: transparent; +} + +.condolence-info-card .van-cell { + min-height: 44px; + padding: 10px 14px; + background: transparent; +} + +.condolence-info-card .van-cell:not(:last-child)::after { + right: 14px; + left: 14px; + border-color: #eef2f7; +} + +.condolence-info-card .van-cell__title { + width: 102px; + color: #596779; + font-size: 12px; + line-height: 24px; + flex: 0 0 102px; +} + +.condolence-info-card .van-cell__value { + min-width: 0; + color: #4f5d70; + font-size: 12px; + line-height: 24px; + text-align: left; + overflow-wrap: anywhere; +} + +.condolence-info-long-cell { + display: block; +} + +.condolence-info-long-cell .van-cell__title { + width: auto; + max-width: 100%; +} + +.condolence-info-long-cell .van-cell__value { + margin-top: 7px; +} + +.condolence-signature-image { + display: block; + max-width: 100%; +} diff --git a/src/main/resources/views/platform/zhghh5/staffbenefit/difficulthelp/common/approval-list.css b/src/main/resources/views/platform/zhghh5/staffbenefit/difficulthelp/common/approval-list.css new file mode 100644 index 0000000..4e72b8f --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/staffbenefit/difficulthelp/common/approval-list.css @@ -0,0 +1,307 @@ +#app { + --color-primary: #1989fa; +} + +.difficult-help-approval-page { + min-height: 100vh; + padding-bottom: calc(24px + env(safe-area-inset-bottom)); + box-sizing: border-box; + background: #f3f7fd; +} + +.difficult-help-approval-page .van-nav-bar, +.difficult-help-approval-page .van-sticky--fixed { + background: #fff; +} + +.difficult-help-approval-page .van-nav-bar__title { + color: #172033; + font-size: 16px; + font-weight: 600; +} + +.difficult-help-approval-page .van-nav-bar .van-icon, +.difficult-help-approval-page .van-nav-bar__text { + color: #1989fa; +} + +.difficult-help-approval-sticky { + padding: 22px 12px 1px; + box-sizing: border-box; + background: #f3f7fd; +} + +.difficult-help-approval-search { + margin: 0 0 8px; + padding: 0; + overflow: hidden; + border-radius: 12px; + background: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .1); +} + +.difficult-help-approval-search .van-search__content { + height: 42px; + padding-left: 12px; + align-items: center; + border-radius: 12px; + background: #fff; +} + +.difficult-help-approval-search .van-field__control { + color: #263548; + font-size: 14px; +} + +.difficult-help-approval-search .van-field__control::placeholder { + color: #a7b0bf; +} + +.difficult-help-approval-filter { + margin-bottom: 10px; + overflow: hidden; + border-radius: 10px; + box-shadow: 0 5px 16px rgba(43, 73, 112, .08); + transition: border-radius .18s ease; +} + +.difficult-help-approval-filter.is-open { + border-radius: 10px 10px 0 0; +} + +.difficult-help-approval-filter .van-dropdown-menu__bar, +.difficult-help-approval-filter .van-dropdown-menu__item, +.difficult-help-approval-filter .van-dropdown-menu__title { + height: 44px; +} + +.difficult-help-approval-filter .van-dropdown-menu__bar { + box-shadow: none; +} + +.difficult-help-approval-filter .van-dropdown-menu__item { + min-width: 0; + align-items: center; + justify-content: center; +} + +.difficult-help-approval-filter .van-dropdown-menu__title { + display: inline-flex; + max-width: calc(100% - 12px); + align-items: center; + color: #66758a; + font-size: 13px; + line-height: 20px; +} + +.difficult-help-approval-filter .van-dropdown-menu__title--active, +.difficult-help-approval-filter .van-dropdown-item__option--active, +.difficult-help-approval-filter .van-dropdown-item__option--active .van-cell__title, +.difficult-help-approval-filter .van-dropdown-item__option--active .van-dropdown-item__icon { + color: #1989fa; +} + +.difficult-help-approval-filter .van-dropdown-item__content { + width: calc(100% - 24px); + max-height: 50%; + margin: 0 12px; + overflow-x: hidden; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + box-sizing: border-box; + border-radius: 0 0 12px 12px; + box-shadow: 0 10px 24px rgba(31, 65, 108, .14); +} + +.difficult-help-approval-filter .van-dropdown-item__option { + display: flex; + min-height: 48px; + padding: 0 16px; + align-items: center; + color: #46566c; + font-size: 14px; +} + +.difficult-help-approval-filter .van-dropdown-item__option .van-cell__title { + display: flex; + min-width: 0; + min-height: 20px; + align-items: center; + flex: 1 1 auto; + line-height: 20px; +} + +.difficult-help-approval-filter .van-dropdown-item__option .van-cell__value { + display: flex; + width: 20px; + min-width: 0; + overflow: visible; + align-items: center; + justify-content: flex-end; + flex: 0 0 20px; +} + +.difficult-help-approval-content { + padding: 0 12px; +} + +.difficult-help-list-skeleton { + padding-bottom: 2px; +} + +.difficult-help-list-skeleton__card { + margin-bottom: 12px; + padding: 14px; + overflow: hidden; + box-sizing: border-box; + border: 1px solid #e9eff7; + border-radius: 12px; + background: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .08); +} + +.difficult-help-list-skeleton__card .van-skeleton { + padding: 0; +} + +.difficult-help-list-skeleton__card .van-skeleton__title { + width: 34%; + height: 17px; + margin-bottom: 13px; +} + +.difficult-help-list-skeleton__card .van-skeleton__row { + height: 12px; + margin-top: 11px; +} + +.difficult-help-list-skeleton__card .van-skeleton__row:nth-child(2n) { + width: 88%; +} + +.difficult-help-list-skeleton__card .van-skeleton__row:last-child { + width: 48%; + margin-top: 18px; +} + +.difficult-help-approval-page .table-list-container { + margin-top: 0; + padding-bottom: 2px; +} + +.difficult-help-approval-page .table-list-container .table-list-item { + margin-bottom: 12px; + padding: 14px; + border: 1px solid #e9eff7; + border-radius: 12px; + box-shadow: 0 5px 16px rgba(43, 73, 112, .08); +} + +.difficult-help-approval-card-header { + display: flex; + margin-bottom: 8px; + align-items: flex-start; + justify-content: space-between; +} + +.difficult-help-approval-card-heading { + min-width: 0; + padding-right: 10px; + flex: 1; +} + +.difficult-help-approval-card-title { + overflow: hidden; + color: #253247; + font-size: 15px; + font-weight: 600; + line-height: 22px; + text-overflow: ellipsis; + white-space: nowrap; +} + +.difficult-help-approval-card-code { + margin-top: 1px; + color: #9ba6b6; + font-size: 12px; + line-height: 18px; +} + +.difficult-help-approval-card-status { + display: inline-flex; + flex: none; +} + +.difficult-help-approval-card-status .van-tag { + min-height: 24px; + padding: 3px 9px; + border: 0; + border-radius: 12px; + box-sizing: border-box; + font-size: 12px; + line-height: 18px; +} + +.difficult-help-approval-page .table-list-container .table-list-item .item-actions { + margin-top: 10px; + padding-top: 10px; + border-top-color: #edf1f6; +} + +.difficult-help-approval-page .table-list-container .table-list-item .action-btn { + min-height: 28px; + padding: 4px 11px; + border-radius: 14px; + color: #1989fa; + background: #eaf4ff; + font-size: 12px; + line-height: 18px; +} + +.difficult-help-approval-page .table-list-container .table-list-item .action-btn.delete { + color: #f04444; + background: #fff0f0; +} + +.difficult-help-approval-page .table-list-container .table-list-item .action-btn .van-icon { + margin-right: 5px; + font-size: 13px; +} + +.difficult-help-approval-page .empty-state { + padding: 0; +} + +.difficult-help-approval-empty { + display: flex; + min-height: 280px; + padding: 46px 18px 36px; + align-items: center; + justify-content: center; + box-sizing: border-box; + flex-direction: column; + text-align: center; +} + +.difficult-help-approval-empty img { + display: block; + width: 86%; + max-width: 290px; + height: auto; + object-fit: contain; +} + +.difficult-help-approval-empty__title { + margin-top: 14px; + color: #50627a; + font-size: 15px; + font-weight: 600; + line-height: 22px; +} + +.difficult-help-approval-empty__hint { + margin-top: 5px; + color: #9aa7b8; + font-size: 12px; + line-height: 18px; +} diff --git a/src/main/resources/views/platform/zhghh5/staffbenefit/difficulthelp/common/info.css b/src/main/resources/views/platform/zhghh5/staffbenefit/difficulthelp/common/info.css new file mode 100644 index 0000000..05966d8 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/staffbenefit/difficulthelp/common/info.css @@ -0,0 +1,353 @@ +.difficult-help-full-popup { + --color-primary: #1989fa; + width: 100%; + height: 100%; + overflow: hidden; + background: #f3f7fc; +} + +.difficult-help-full-popup__page { + display: flex; + height: 100%; + padding-top: 46px; + overflow: hidden; + box-sizing: border-box; + flex-direction: column; +} + +.difficult-help-full-popup__page > .van-nav-bar { + z-index: 20; + background: #fff; +} + +.difficult-help-full-popup__page > .van-nav-bar .van-icon, +.difficult-help-full-popup__page > .van-nav-bar .van-nav-bar__text { + color: #1989fa; +} + +.difficult-help-full-popup__scroll { + min-height: 0; + overflow-y: auto; + flex: 1; + -webkit-overflow-scrolling: touch; +} + +.difficult-help-info-main { + padding: 12px 15px calc(18px + env(safe-area-inset-bottom)); +} + +.difficult-help-info-card { + margin-bottom: 11px; + overflow: hidden; + border: 1px solid #e9eff7; + border-radius: 10px; + background: #fff; + box-shadow: 0 3px 11px rgba(51, 87, 126, .08); +} + +.difficult-help-info-card__title { + position: relative; + margin: 0; + padding: 12px 14px 8px 21px; + color: #354255; + font-size: 15px; + font-weight: 600; + line-height: 22px; +} + +.difficult-help-info-card__title::before { + position: absolute; + top: 15px; + bottom: 11px; + left: 12px; + width: 2px; + border-radius: 2px; + background: #1989fa; + content: ""; +} + +.difficult-help-audit-card__required { + margin-left: 4px; + color: #ee0a24; + font-size: 14px; +} + +.difficult-help-audit-form { + padding-bottom: 4px; +} + +.difficult-help-info-card .van-field.difficult-help-audit-select, +.difficult-help-info-card .van-field.difficult-help-audit-money { + min-height: 48px; + padding: 11px 14px; +} + +.difficult-help-info-card .van-field.difficult-help-audit-select .van-field__label, +.difficult-help-info-card .van-field.difficult-help-audit-money .van-field__label { + width: 88px; + color: #596779; + font-size: 12px; +} + +.difficult-help-info-card .van-field.difficult-help-audit-select .van-field__control, +.difficult-help-info-card .van-field.difficult-help-audit-money .van-field__control { + color: #253247; + font-size: 13px; +} + +.difficult-help-info-card .van-field.difficult-help-audit-textarea { + width: calc(100% - 28px); + margin: 0 14px 14px; + padding: 12px; + box-sizing: border-box; + border: 1px solid #c9d5e5; + border-radius: 10px; + background: #f7f9fd; +} + +.difficult-help-info-card .van-field.difficult-help-audit-textarea .van-field__control { + min-height: 132px; + color: #253247; + font-size: 13px; + line-height: 22px; +} + +.difficult-help-info-card .van-field.difficult-help-audit-textarea .van-field__control::placeholder, +.difficult-help-info-card .van-field.difficult-help-audit-select .van-field__control::placeholder, +.difficult-help-info-card .van-field.difficult-help-audit-money .van-field__control::placeholder { + color: #9aa7b8; +} + +.difficult-help-info-card .van-field.difficult-help-audit-textarea .van-field__word-limit { + color: #718096; +} + +.difficult-help-info-card .van-field.difficult-help-audit-textarea::after { + display: none; +} + +.difficult-help-popup-actions { + display: flex; + padding: 10px 0 calc(12px + env(safe-area-inset-bottom)); + justify-content: space-between; + column-gap: 10px; + background: transparent; +} + +.difficult-help-popup-actions .van-button { + min-width: 0; + border-radius: 14px; +} + +.difficult-help-popup-actions .difficult-help-action-primary { + border-color: #1989fa; + background: #1989fa; +} + +.difficult-help-popup-actions .difficult-help-action-danger { + border-color: #ff4d4f; + background: #ff4d4f; +} + +.difficult-help-info-card .van-cell-group { + margin: 0; + background: transparent; +} + +.difficult-help-info-card .van-cell { + min-height: 44px; + padding: 10px 14px; + background: transparent; +} + +.difficult-help-info-card .van-cell:not(:last-child)::after { + right: 14px; + left: 14px; + border-color: #eef2f7; +} + +.difficult-help-info-card .van-cell__title { + width: 112px; + color: #596779; + font-size: 12px; + line-height: 24px; + flex: 0 0 112px; +} + +.difficult-help-info-card .van-cell__value { + min-width: 0; + color: #4f5d70; + font-size: 12px; + line-height: 24px; + text-align: left; + overflow-wrap: anywhere; +} + +.difficult-help-info-long-cell { + display: block; +} + +.difficult-help-info-long-cell .van-cell__title { + width: auto; + max-width: 100%; +} + +.difficult-help-info-long-cell .van-cell__value { + margin-top: 7px; +} + +.difficult-help-info-pre-line { + white-space: pre-line; + overflow-wrap: anywhere; +} + +.difficult-help-family-list { + padding: 0 14px 14px; +} + +.difficult-help-family-item { + overflow: hidden; + border: 1px solid #e5edf7; + border-radius: 10px; + background: #fff; + box-shadow: 0 2px 8px rgba(51, 87, 126, .06); +} + +.difficult-help-family-item + .difficult-help-family-item { + margin-top: 10px; +} + +.difficult-help-family-header { + display: flex; + min-height: 44px; + padding: 9px 11px; + align-items: center; + box-sizing: border-box; + background: linear-gradient(90deg, #f0f6ff 0%, #f8fbff 100%); +} + +.difficult-help-family-index { + display: inline-flex; + width: 24px; + height: 24px; + margin-right: 8px; + align-items: center; + justify-content: center; + flex: 0 0 24px; + border-radius: 50%; + color: #fff; + background: #1989fa; + font-size: 12px; + font-weight: 600; +} + +.difficult-help-family-name { + min-width: 0; + overflow: hidden; + color: #2f3d51; + font-size: 14px; + font-weight: 600; + line-height: 22px; + text-overflow: ellipsis; + white-space: nowrap; + flex: 1; +} + +.difficult-help-family-relation { + max-width: 92px; + margin-left: 8px; + padding: 2px 8px; + overflow: hidden; + border-radius: 10px; + color: #1989fa; + background: #e7f2ff; + font-size: 11px; + line-height: 18px; + text-overflow: ellipsis; + white-space: nowrap; + flex: none; +} + +.difficult-help-family-summary { + display: grid; + margin: 0 11px; + padding: 11px 0; + grid-template-columns: repeat(2, minmax(0, 1fr)); + border-bottom: 1px solid #eef2f7; +} + +.difficult-help-family-summary__item { + min-width: 0; + padding: 0 8px; +} + +.difficult-help-family-summary__item:first-child { + padding-left: 0; + border-right: 1px solid #eef2f7; +} + +.difficult-help-family-summary__item span, +.difficult-help-family-summary__item strong, +.difficult-help-family-detail__row span, +.difficult-help-family-detail__row strong { + display: block; + overflow-wrap: anywhere; +} + +.difficult-help-family-summary__item span, +.difficult-help-family-detail__row span { + color: #909bac; + font-size: 11px; + line-height: 17px; +} + +.difficult-help-family-summary__item strong { + margin-top: 3px; + color: #435167; + font-size: 13px; + font-weight: 500; + line-height: 20px; +} + +.difficult-help-family-detail { + padding: 4px 11px 7px; +} + +.difficult-help-family-detail__row { + display: grid; + padding: 7px 0; + grid-template-columns: 68px minmax(0, 1fr); + column-gap: 8px; +} + +.difficult-help-family-detail__row strong { + color: #536176; + font-size: 12px; + font-weight: 400; + line-height: 18px; +} + +.difficult-help-info-card .van-empty { + padding: 12px 0 20px; +} + +.difficult-help-info-promise { + color: #4f5d70; + font-size: 12px; + line-height: 21px; +} + +.difficult-help-info-commitment { + display: flex; + margin-top: 8px; + align-items: flex-end; + color: #8995a6; + font-size: 11px; + line-height: 18px; + flex-direction: column; +} + +.difficult-help-signature-image { + display: block; + max-width: 100%; +} diff --git a/src/main/resources/views/platform/zhghh5/staffmanage/member/theme.css b/src/main/resources/views/platform/zhghh5/staffmanage/member/theme.css new file mode 100644 index 0000000..517cbb7 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/staffmanage/member/theme.css @@ -0,0 +1,524 @@ +:root { + --member-primary: #1989fa; + --member-page-bg: #f3f7fd; + --member-text: #263548; + --member-muted: #8c98aa; + --member-border: #e8eef6; + --color-primary: #1989fa; +} + +body { + background: var(--member-page-bg); +} + +.member-h5-page { + min-height: 100vh; + padding-bottom: calc(24px + env(safe-area-inset-bottom)); + box-sizing: border-box; + color: var(--member-text); + background: var(--member-page-bg); +} + +.member-h5-page.has-fixed-actions { + padding-bottom: calc(78px + env(safe-area-inset-bottom)); +} + +.member-h5-page .van-nav-bar { + background: #fff; +} + +.member-h5-page .van-nav-bar__title { + color: #1f2937; + font-size: 16px; + font-weight: 600; +} + +.member-h5-page .van-nav-bar .van-icon, +.member-h5-page .van-nav-bar__text { + color: var(--member-primary); +} + +.member-hero { + position: relative; + height: 116px; + padding: 18px 18px 0; + overflow: hidden; + box-sizing: border-box; + background-color: #edf5ff; + background-image: url("/assets/mobile/img/home/v4/hero-campus.png"); + background-position: 66% 46%; + background-size: cover; +} + +.member-hero::after { + position: absolute; + inset: 0; + background: rgba(242, 247, 255, .76); + content: ""; +} + +.member-hero__content { + position: relative; + z-index: 1; +} + +.member-hero__title { + color: var(--member-primary); + font-size: 23px; + font-weight: 700; + line-height: 30px; + letter-spacing: 1px; +} + +.member-hero__subtitle { + margin-top: 2px; + color: #718096; + font-size: 11px; + line-height: 18px; +} + +.member-page-main { + position: relative; + z-index: 2; + margin-top: -34px; + padding: 0 12px; +} + +.member-toolbar { + padding: 10px; + border: 1px solid var(--member-border); + border-radius: 12px; + background: rgba(255, 255, 255, .98); + box-shadow: 0 5px 16px rgba(43, 73, 112, .09); +} + +.member-toolbar .van-search { + padding: 0; + background: transparent; +} + +.member-toolbar .van-search__content { + height: 42px; + align-items: center; + border-radius: 10px; + background: #f5f8fc; +} + +.member-toolbar .van-field__control { + color: var(--member-text); + font-size: 14px; +} + +.member-toolbar .van-search__action { + padding: 0 4px 0 12px; + color: var(--member-primary); + font-size: 14px; +} + +.member-toolbar .van-dropdown-menu { + margin-top: 8px; + /* Vant 下拉选项弹层位于菜单内部,吸顶状态下必须允许弹层超出筛选卡片显示。 */ + overflow: visible; + border-top: 1px solid #edf1f6; +} + +.member-toolbar .van-dropdown-menu__bar { + height: 42px; + background: transparent; +} + +.member-toolbar .van-dropdown-menu__title { + color: #66758a; + font-size: 13px; +} + +.member-list-section { + margin-top: 10px; +} + +.member-list-section .table-list-container { + margin-top: 0; +} + +.member-list-section .table-list-item { + border-color: var(--member-border) !important; + border-radius: 12px !important; + box-shadow: 0 7px 20px rgba(55, 85, 126, .08) !important; +} + +.member-list-section .item-title { + color: #263548 !important; + font-size: 15px !important; +} + +.member-list-section .action-btn { + color: var(--member-primary) !important; + background: #eaf4ff !important; +} + +.member-list-section .action-btn.delete { + color: #e95757 !important; + background: #fff0f0 !important; +} + +.member-empty { + display: flex; + min-height: 280px; + padding: 20px 18px 30px; + align-items: center; + justify-content: flex-start; + flex-direction: column; + box-sizing: border-box; + text-align: center; +} + +.member-empty img { + display: block; + width: 84%; + max-width: 290px; + height: auto; + object-fit: contain; +} + +.member-empty__title { + margin-top: -8px; + color: #50627a; + font-size: 15px; + line-height: 22px; + font-weight: 500; +} + +.member-empty__hint { + margin-top: 6px; + color: #9aa7b8; + font-size: 12px; + line-height: 18px; +} + +.member-list-skeleton { + padding-top: 10px; +} + +.member-list-skeleton__card { + min-height: 154px; + margin-bottom: 10px; + padding: 14px; + border-radius: 12px; + background: #fff; + box-sizing: border-box; + box-shadow: 0 7px 20px rgba(55, 85, 126, .08); +} + +.member-list-skeleton__card .van-skeleton { + padding: 0; +} + +.member-list-skeleton__card .van-skeleton__title { + height: 17px; +} + +.member-list-skeleton__card .van-skeleton__row { + height: 12px; + margin-top: 13px; +} + +/* 页面首次进入时统一遮住尚未完成初始化的横幅、筛选栏和列表,避免返回页面时出现空筛选项。 */ +.member-page-skeleton { + min-height: calc(100vh - 46px); + padding: 12px; + box-sizing: border-box; + background: var(--member-page-bg); +} + +.member-page-skeleton__hero { + height: 82px; + margin-bottom: 10px; + padding: 18px; + border-radius: 12px; + background: linear-gradient(135deg, #e4f1ff 0%, #f2f7ff 100%); + box-sizing: border-box; +} + +.member-page-skeleton__toolbar { + min-height: 96px; + margin-bottom: 10px; + padding: 14px; + border-radius: 12px; + background: #fff; + box-sizing: border-box; + box-shadow: 0 5px 16px rgba(43, 73, 112, .07); +} + +.member-page-skeleton__toolbar .van-skeleton, +.member-page-skeleton__hero .van-skeleton { + padding: 0; +} + +.member-page-skeleton__cards .member-list-skeleton { + padding-top: 0; +} + +.member-count-chip { + display: inline-flex; + height: 28px; + margin: 10px 0 0; + padding: 0 11px; + align-items: center; + border-radius: 14px; + color: #397de0; + background: #edf5ff; + font-size: 12px; +} + +.member-form-intro { + display: flex; + min-height: 58px; + margin-bottom: 10px; + padding: 11px 12px; + align-items: flex-start; + box-sizing: border-box; + border: 1px solid #dfeafb; + border-radius: 10px; + background: rgba(246, 250, 255, .98); + box-shadow: 0 3px 10px rgba(53, 98, 154, .08); +} + +.member-form-intro .van-icon { + margin: 1px 9px 0 0; + color: var(--member-primary); + font-size: 19px; +} + +.member-form-intro__title { + color: var(--member-primary); + font-size: 12px; + line-height: 18px; + font-weight: 600; +} + +.member-form-intro__text { + margin-top: 2px; + color: #8a97a8; + font-size: 10px; + line-height: 17px; +} + +.member-application-form.form-container { + padding-bottom: 0; + background: transparent; +} + +.member-application-form .form-section { + margin-bottom: 11px; + overflow: hidden; + border: 1px solid #e9eff7; + border-radius: 10px; + background: #fff; + box-shadow: 0 3px 11px rgba(51, 87, 126, .08); +} + +.member-form-section__title { + position: relative; + margin: 0; + padding: 12px 14px 8px 21px; + color: #354255; + background: #fff; + font-size: 13px; + line-height: 20px; + font-weight: 600; +} + +.member-form-section__title::before { + position: absolute; + top: 15px; + bottom: 11px; + left: 12px; + width: 2px; + border-radius: 2px; + background: var(--member-primary); + content: ""; +} + +.member-application-form .form-section > .van-cell-group { + margin: 0; + background: transparent; +} + +.member-application-form .van-cell { + min-height: 44px; + padding: 10px 14px; + background: #fff; +} + +.member-application-form .van-field__label { + width: 84px; + color: #596779; + font-size: 12px; + line-height: 24px; +} + +.member-application-form .van-field__control, +.member-application-form .van-field__value { + color: #4f5d70; + font-size: 12px; + line-height: 24px; +} + +.member-form-actions, +.member-approval-actions { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 100; + display: flex; + gap: 9px; + padding: 10px 12px calc(10px + env(safe-area-inset-bottom)); + border-top: 1px solid #edf1f6; + background: rgba(255, 255, 255, .98); + box-sizing: border-box; + box-shadow: 0 -4px 14px rgba(50, 78, 112, .06); +} + +.member-form-actions .van-button, +.member-approval-actions .van-button { + height: 42px; + margin: 0; + border-radius: 14px; + font-size: 14px; +} + +.member-form-actions .member-save-button { + color: var(--member-primary); + border-color: var(--member-primary); + background: #fff; +} + +.member-form-actions .member-submit-button, +.member-approval-actions .member-agree-button { + color: #fff; + border-color: var(--member-primary); + background: var(--member-primary); +} + +.member-approval-actions .member-return-button { + color: #fff; + border-color: #e6a23c; + background: #e6a23c; +} + +.member-form-skeleton { + padding: 0 12px 24px; +} + +.member-form-skeleton__card { + min-height: 200px; + margin-bottom: 10px; + padding: 16px 14px; + border-radius: 12px; + background: #fff; + box-sizing: border-box; +} + +.member-form-skeleton__card .van-skeleton { + padding: 0; +} + +.member-full-popup { + width: 100%; + height: 100%; + overflow: hidden; + background: var(--member-page-bg); +} + +.member-full-popup__page { + display: flex; + height: 100%; + padding-top: 46px; + overflow: hidden; + box-sizing: border-box; + flex-direction: column; +} + +.member-full-popup__page > .van-nav-bar { + z-index: 20; + background: #fff; +} + +.member-full-popup__page > .van-nav-bar .van-nav-bar__title { + color: #172033; + font-size: 16px; + font-weight: 600; +} + +.member-full-popup__page > .van-nav-bar .van-icon, +.member-full-popup__page > .van-nav-bar .van-nav-bar__text { + color: var(--member-primary); +} + +.member-info-scroll { + min-height: 0; + padding: 12px 12px calc(82px + env(safe-area-inset-bottom)); + overflow-y: auto; + flex: 1; + box-sizing: border-box; + -webkit-overflow-scrolling: touch; +} + +.member-detail-card { + margin-bottom: 11px; + overflow: hidden; + border: 1px solid #e9eff7; + border-radius: 10px; + background: #fff; + box-shadow: 0 3px 11px rgba(51, 87, 126, .08); +} + +.member-detail-card__title { + position: relative; + padding: 12px 14px 8px 21px; + color: #354255; + font-size: 13px; + line-height: 20px; + font-weight: 600; +} + +.member-detail-card__title::before { + position: absolute; + top: 15px; + bottom: 11px; + left: 12px; + width: 2px; + border-radius: 2px; + background: var(--member-primary); + content: ""; +} + +.member-detail-card .van-cell { + padding: 10px 14px; + color: #4f5d70; + font-size: 12px; +} + +.member-detail-card .van-cell__title { + color: #7b899b; +} + +@media (min-width: 600px) { + .member-hero__content, + .member-page-main, + .member-form-skeleton { + max-width: 520px; + margin-right: auto; + margin-left: auto; + box-sizing: border-box; + } + + .member-form-actions, + .member-approval-actions { + right: 50%; + left: auto; + width: 520px; + transform: translateX(50%); + } +} diff --git a/src/main/resources/views/platform/zhghh5/welfare/address/addressManager.js b/src/main/resources/views/platform/zhghh5/welfare/address/addressManager.js new file mode 100644 index 0000000..8e11180 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/welfare/address/addressManager.js @@ -0,0 +1,1067 @@ +const WELFARE_ADDRESS_MANAGER_COMPONENT = { + template: /*language=HTML*/ ` +
+
+ +
+ +
+
+ 地址加载中... +
+ +
+ 收货地址空状态插画 +
暂无收货地址
+
添加收货地址后即可使用
+
+
+ + + + +
+ +
+
+ + +
+
+ + + + + + + + +
+
+ +
+
+ + + + + + +
+
删除地址
+
删除后无法恢复,确定删除当前收货地址吗?
+
+ + +
+
+
+
+ `, + props: { + pageTitle: { + type: String, + default: "地址管理" + }, + selectable: { + type: Boolean, + default: false + }, + /** + * selectable 为 true 时,控制是否展示“当前选择”标记和选中高亮;传 false 仅隐藏视觉状态,不影响 selectable 的点选回填能力。 + */ + showSelectedBadge: { + type: Boolean, + default: true + }, + // 地址管理页和福利选择弹框使用紧凑卡片列表,其他复用入口继续使用原卡片结构。 + flatList: { + type: Boolean, + default: false + }, + selectedAddressText: { + type: String, + default: "" + }, + areaList: { + type: Object, + required: true + } + }, + data() { + return { + addressLoading: false, + addressList: [], + deleteTargetAddress: null, + swipeAddressId: "", + swipeOffset: 0, + swipeStartX: 0, + swipeStartY: 0, + swipeStartOffset: 0, + swipeDirection: "", + swipeDragging: false, + swipeMoved: false, + swipeDeleteWidth: 78, + showAddressEditPopup: false, + showAddressAreaPopup: false, + showDeleteDialog: false, + addressEditTitle: "新增地址", + addressAreaCode: "", + addressRecognitionText: "", + addressFormLoading: false, + addressDeleteLoading: false, + editingSelectedAddress: false, + historyLayerUnsubscribe: null, + historyLayerNames: { + edit: "", + area: "", + deleteConfirm: "" + }, + addressForm: { + id: "", + userName: "", + tel: "", + province: "", + city: "", + county: "", + addressDetail: "", + areaCode: "", + isDefault: false + }, + addressFormErrors: { + userName: false, + tel: false, + area: false, + addressDetail: false + } + } + }, + computed: { + addressRegionText() { + return [this.addressForm.province, this.addressForm.city, this.addressForm.county] + .filter((item) => !!item) + .join(" / ") + } + }, + methods: { + // 组件只订阅全局历史栈,由所在页面统一注册,避免覆盖父页面的弹层回调。 + subscribeHistoryLayers() { + const manager = window.h5HistoryLayerManager + if (!manager || typeof manager.subscribe !== "function") return + this.historyLayerNames.edit = "welfare-address-edit-" + this._uid + this.historyLayerNames.area = "welfare-address-area-" + this._uid + this.historyLayerNames.deleteConfirm = "welfare-address-delete-" + this._uid + this.historyLayerUnsubscribe = manager.subscribe((stack) => { + this.showAddressEditPopup = stack.includes(this.historyLayerNames.edit) + this.showAddressAreaPopup = stack.includes(this.historyLayerNames.area) + this.showDeleteDialog = stack.includes(this.historyLayerNames.deleteConfirm) + }) + }, + openHistoryLayer(layerName) { + const manager = window.h5HistoryLayerManager + if (manager && manager.open(layerName)) return + this.setHistoryLayerVisible(layerName, true) + }, + closeHistoryLayer(layerName, afterClose = null) { + const manager = window.h5HistoryLayerManager + if (manager && manager.close(layerName, afterClose)) return + this.setHistoryLayerVisible(layerName, false) + if (typeof afterClose === "function") afterClose() + }, + setHistoryLayerVisible(layerName, visible) { + if (layerName === this.historyLayerNames.edit) this.showAddressEditPopup = visible + if (layerName === this.historyLayerNames.area) this.showAddressAreaPopup = visible + if (layerName === this.historyLayerNames.deleteConfirm) this.showDeleteDialog = visible + }, + handleHistoryLayerComponentClose(layerName) { + const manager = window.h5HistoryLayerManager + if (!manager) return + const stack = manager.stack + if (stack[stack.length - 1] === layerName) manager.close(layerName) + }, + handlePageBack() { + this.$emit("back") + }, + /** + * 查询当前用户地址。请求不传业务参数;接口返回 Result,data 为地址对象数组;返回 Promise。 + */ + selectUserAddress() { + if (this.addressLoading) return Promise.resolve() + this.addressLoading = true + return this.$axios.post("/platform/welfare/addressManage/selectUserAddress", {}) + .then((resp) => { + if (resp.code === 0) { + this.$set(this, "addressList", resp.data || []) + this.closeAddressSwipe() + } else { + this.$toast.fail(resp.msg) + } + }) + .catch(() => { + this.$toast.fail("地址加载失败,请稍后重试") + }) + .finally(() => { + this.addressLoading = false + }) + }, + getAddressText(address) { + if (!address) return "" + return (address.province || "") + (address.city || "") + (address.county || "") + + (address.addressDetail || "") + }, + isAddressSelected(address) { + return this.selectable && !!this.selectedAddressText && + this.selectedAddressText === this.getAddressText(address) + }, + showAddressBadge(address) { + return this.selectable && this.showSelectedBadge ? this.isAddressSelected(address) : !!address.isDefault + }, + getAddressSwipeStyle(addressId) { + const offset = this.swipeAddressId === addressId ? this.swipeOffset : 0 + return {transform: "translate3d(" + offset + "px, 0, 0)"} + }, + /** + * 记录卡片触摸起点。event 提供触点坐标,address 提供地址 ID;无返回值。 + */ + handleAddressTouchStart(event, address) { + const touch = event.touches && event.touches[0] + if (!touch || !address || !address.id) return + if (this.swipeAddressId && this.swipeAddressId !== address.id) this.closeAddressSwipe() + if (this.swipeAddressId !== address.id) { + this.swipeAddressId = address.id + this.swipeOffset = 0 + } + this.swipeStartX = touch.clientX + this.swipeStartY = touch.clientY + this.swipeStartOffset = this.swipeOffset + this.swipeDirection = "" + this.swipeDragging = false + this.swipeMoved = false + }, + // 横向位移超过 5 像素后锁定为左滑,纵向手势继续用于列表滚动。 + handleAddressTouchMove(event, address) { + if (!address || this.swipeAddressId !== address.id) return + const touch = event.touches && event.touches[0] + if (!touch) return + const moveX = touch.clientX - this.swipeStartX + const moveY = touch.clientY - this.swipeStartY + if (!this.swipeDirection) { + if (Math.max(Math.abs(moveX), Math.abs(moveY)) < 5) return + this.swipeDirection = Math.abs(moveX) > Math.abs(moveY) ? "horizontal" : "vertical" + } + if (this.swipeDirection !== "horizontal") { + this.swipeMoved = true + return + } + event.preventDefault() + this.swipeDragging = true + this.swipeMoved = true + const nextOffset = this.swipeStartOffset + moveX + this.swipeOffset = Math.max(-this.swipeDeleteWidth, Math.min(0, nextOffset)) + }, + handleAddressTouchEnd(address) { + if (!address || this.swipeAddressId !== address.id) return + if (this.swipeDirection === "horizontal") { + const shouldOpen = this.swipeOffset <= -(this.swipeDeleteWidth / 2) + this.swipeOffset = shouldOpen ? -this.swipeDeleteWidth : 0 + if (!shouldOpen) this.swipeAddressId = "" + } else if (this.swipeOffset === 0) { + this.swipeAddressId = "" + } + this.swipeDragging = false + this.swipeDirection = "" + }, + handleAddressCardClick(address) { + if (this.swipeMoved) { + this.swipeMoved = false + return + } + if (this.swipeAddressId === address.id && this.swipeOffset < 0) { + this.closeAddressSwipe() + return + } + if (this.selectable) this.$emit("select", address) + }, + closeAddressSwipe() { + this.swipeAddressId = "" + this.swipeOffset = 0 + this.swipeStartOffset = 0 + this.swipeDirection = "" + this.swipeDragging = false + this.swipeMoved = false + }, + resetAddressFormErrors() { + Object.keys(this.addressFormErrors).forEach((fieldName) => { + this.$set(this.addressFormErrors, fieldName, false) + }) + }, + clearAddressFormError(fieldName) { + if (!Object.prototype.hasOwnProperty.call(this.addressFormErrors, fieldName)) return + this.$set(this.addressFormErrors, fieldName, false) + }, + /** + * 打开新增或编辑页。address 为可选地址对象;无返回值,回显后打开组件专属历史层。 + */ + openAddressEdit(address = null) { + const sourceAddress = address || {} + this.closeAddressSwipe() + this.addressEditTitle = sourceAddress.id ? "编辑地址" : "新增地址" + this.editingSelectedAddress = !!sourceAddress.id && this.isAddressSelected(sourceAddress) + this.addressAreaCode = sourceAddress.areaCode || "" + this.$set(this, "addressRecognitionText", "") + this.$set(this, "addressForm", { + id: sourceAddress.id || "", + userName: sourceAddress.userName || "", + tel: sourceAddress.tel || "", + province: sourceAddress.province || "", + city: sourceAddress.city || "", + county: sourceAddress.county || "", + addressDetail: sourceAddress.addressDetail || "", + areaCode: sourceAddress.areaCode || "", + isDefault: !!sourceAddress.isDefault + }) + this.resetAddressFormErrors() + this.openHistoryLayer(this.historyLayerNames.edit) + }, + getRecognitionAreaAliases(name) { + const areaName = (name || "").trim() + if (!areaName) return [] + const shortName = areaName.replace(/特别行政区$|维吾尔自治区$|壮族自治区$|回族自治区$|自治区$|自治州$|地区$|盟$|省$|市$|区$|县$/, "") + return shortName && shortName !== areaName && shortName.length >= 2 + ? [areaName, shortName] + : [areaName] + }, + /** + * 在地区字典中查找文本内最明确的地区。返回匹配对象,未匹配返回 null。 + */ + findRecognitionArea(areaMap, sourceText, codePrefix = "") { + let bestMatch = null + Object.keys(areaMap || {}).forEach((areaCode) => { + if (codePrefix && areaCode.indexOf(codePrefix) !== 0) return + const areaName = areaMap[areaCode] + this.getRecognitionAreaAliases(areaName).forEach((alias) => { + const matchIndex = sourceText.indexOf(alias) + if (matchIndex < 0) return + if (!bestMatch || alias.length > bestMatch.alias.length || + (alias.length === bestMatch.alias.length && matchIndex < bestMatch.index)) { + bestMatch = {code: areaCode, name: areaName, alias: alias, index: matchIndex} + } + }) + }) + return bestMatch + }, + parseRecognitionRegion(sourceText) { + let provinceMatch = this.findRecognitionArea(this.areaList.province_list, sourceText) + const provincePrefix = provinceMatch ? provinceMatch.code.slice(0, 2) : "" + let cityMatch = this.findRecognitionArea(this.areaList.city_list, sourceText, provincePrefix) + const cityPrefix = cityMatch ? cityMatch.code.slice(0, 4) : provincePrefix + const countyMatch = this.findRecognitionArea(this.areaList.county_list, sourceText, cityPrefix) + if (!cityMatch && countyMatch) { + const cityCode = countyMatch.code.slice(0, 4) + "00" + if (this.areaList.city_list[cityCode]) { + cityMatch = {code: cityCode, name: this.areaList.city_list[cityCode], alias: "", index: countyMatch.index} + } + } + if (!provinceMatch && (cityMatch || countyMatch)) { + const childCode = cityMatch ? cityMatch.code : countyMatch.code + const provinceCode = childCode.slice(0, 2) + "0000" + if (this.areaList.province_list[provinceCode]) { + provinceMatch = { + code: provinceCode, + name: this.areaList.province_list[provinceCode], + alias: "", + index: cityMatch ? cityMatch.index : countyMatch.index + } + } + } + if (!provinceMatch || !cityMatch || !countyMatch) return null + return { + province: provinceMatch.name, + city: cityMatch.name, + county: countyMatch.name, + areaCode: countyMatch.code, + matches: [provinceMatch, cityMatch, countyMatch].filter((item) => !!item.alias) + } + }, + cleanRecognitionText(value) { + return (value || "") + .replace(/(?:收件人|收货人|联系人|姓名|手机号码|手机号|联系电话|电话|收货地址|详细地址|地址)\s*[::]?/g, " ") + .replace(/^[\s,,;;、|]+|[\s,,;;、|]+$/g, "") + .replace(/\s+/g, " ") + .trim() + }, + /** + * 识别姓名、11 位手机号、省市区和详细地址;成功后回填 addressForm,无返回值。 + */ + recognizeAddress() { + const sourceText = (this.addressRecognitionText || "").replace(/[\r\n\t]+/g, " ").replace(/\s+/g, " ").trim() + if (!sourceText) { + this.$toast.fail("请先粘贴收货信息") + return + } + const mobileMatch = sourceText.match(/(?:\+?86[-\s]?)?(1[3-9]\d{9})/) + if (!mobileMatch) { + this.$toast.fail("未识别到正确的11位手机号码") + return + } + const regionResult = this.parseRecognitionRegion(sourceText) + if (!regionResult || regionResult.matches.length === 0) { + this.$toast.fail("未识别到完整的省、市、区,请检查后重试") + return + } + const matchedRegions = regionResult.matches.slice().sort((left, right) => left.index - right.index) + const firstRegionIndex = matchedRegions[0].index + const lastRegion = matchedRegions[matchedRegions.length - 1] + const mobileIndex = sourceText.indexOf(mobileMatch[0]) + let userName = this.cleanRecognitionText(sourceText.slice(0, Math.min(mobileIndex, firstRegionIndex))) + let addressDetail = this.cleanRecognitionText( + sourceText.slice(lastRegion.index + lastRegion.alias.length).replace(mobileMatch[0], " ") + ) + if (!userName || !addressDetail) { + let remainingText = sourceText.replace(mobileMatch[0], " ") + matchedRegions.forEach((item) => { + remainingText = remainingText.replace(item.alias, " ") + }) + const remainingParts = this.cleanRecognitionText(remainingText).split(" ").filter((item) => !!item) + if (!userName && remainingParts.length) userName = remainingParts.shift() + if (!addressDetail && remainingParts.length) addressDetail = remainingParts.join("") + } + if (!userName || !addressDetail) { + this.$toast.fail("姓名或详细地址识别不完整,请调整内容后重试") + return + } + if (userName.length > 50 || addressDetail.length > 100) { + this.$toast.fail("姓名或详细地址内容过长,请精简后重试") + return + } + this.$set(this.addressForm, "userName", userName) + this.$set(this.addressForm, "tel", mobileMatch[1]) + this.$set(this.addressForm, "province", regionResult.province) + this.$set(this.addressForm, "city", regionResult.city) + this.$set(this.addressForm, "county", regionResult.county) + this.$set(this.addressForm, "addressDetail", addressDetail) + this.$set(this.addressForm, "areaCode", regionResult.areaCode) + this.$set(this, "addressAreaCode", regionResult.areaCode) + this.resetAddressFormErrors() + this.$toast.success("收货信息识别成功") + }, + openAddressArea() { + this.clearAddressFormError("area") + this.openHistoryLayer(this.historyLayerNames.area) + }, + /** + * values 为省、市、区对象数组;回填名称和编码并关闭地区弹层,无返回值。 + */ + confirmAddressArea(values) { + if (!Array.isArray(values) || values.length < 3) { + this.$toast.fail("请选择完整的省、市、区") + return + } + this.$set(this.addressForm, "province", values[0].name || "") + this.$set(this.addressForm, "city", values[1].name || "") + this.$set(this.addressForm, "county", values[2].name || "") + this.$set(this.addressForm, "areaCode", values[2].code || "") + this.addressAreaCode = values[2].code || "" + this.clearAddressFormError("area") + this.closeHistoryLayer(this.historyLayerNames.area) + }, + validateAddressForm() { + const userName = (this.addressForm.userName || "").trim() + const tel = (this.addressForm.tel || "").trim() + const addressDetail = (this.addressForm.addressDetail || "").trim() + this.$set(this.addressForm, "userName", userName) + this.$set(this.addressForm, "tel", tel) + this.$set(this.addressForm, "addressDetail", addressDetail) + this.resetAddressFormErrors() + if (!userName) { + this.$set(this.addressFormErrors, "userName", true) + this.$toast.fail("请输入收货人姓名") + return false + } + if (!/^1[3-9]\d{9}$/.test(tel)) { + this.$set(this.addressFormErrors, "tel", true) + this.$toast.fail("请输入正确的11位手机号码") + return false + } + if (!this.addressForm.province || !this.addressForm.city || !this.addressForm.county) { + this.$set(this.addressFormErrors, "area", true) + this.$toast.fail("请选择完整的省、市、区") + return false + } + if (!addressDetail) { + this.$set(this.addressFormErrors, "addressDetail", true) + this.$toast.fail("请输入详细地址") + return false + } + return true + }, + /** + * 保存地址。data 为地址 JSON 字符串;接口返回 Result,code=0 表示成功;返回 Promise。 + */ + saveAddress() { + if (this.addressFormLoading || !this.validateAddressForm()) return + const addressPayload = { + userName: this.addressForm.userName, + tel: this.addressForm.tel, + province: this.addressForm.province, + city: this.addressForm.city, + county: this.addressForm.county, + addressDetail: this.addressForm.addressDetail, + areaCode: this.addressForm.areaCode, + isDefault: this.addressForm.isDefault + } + const isEdit = !!this.addressForm.id + if (isEdit) addressPayload.id = this.addressForm.id + this.addressFormLoading = true + return this.$axios.post("/platform/welfare/addressManage/doSaveUserAddress", { + data: JSON.stringify(addressPayload) + }).then((resp) => { + if (resp.code !== 0) { + this.$toast.fail(resp.msg) + return + } + if (this.editingSelectedAddress) this.$emit("selected-address-updated", addressPayload) + this.$toast.success(resp.msg || (isEdit ? "地址修改成功" : "地址新增成功")) + this.closeHistoryLayer(this.historyLayerNames.edit, () => { + this.selectUserAddress() + }) + }).catch(() => { + this.$toast.fail("地址保存失败,请稍后重试") + }).finally(() => { + this.addressFormLoading = false + }) + }, + openDeleteConfirm(address) { + if (!address || !address.id) return + this.$set(this, "deleteTargetAddress", address) + this.closeAddressSwipe() + this.openHistoryLayer(this.historyLayerNames.deleteConfirm) + }, + /** + * 删除当前左滑地址。id 为地址主键;接口返回 Result,code=0 表示成功;返回 Promise。 + */ + deleteAddress() { + if (this.addressDeleteLoading || !this.deleteTargetAddress || !this.deleteTargetAddress.id) return + this.addressDeleteLoading = true + return this.$axios.post("/platform/welfare/addressManage/deleteAddress", { + id: this.deleteTargetAddress.id + }).then((resp) => { + if (resp.code !== 0) { + this.$toast.fail(resp.msg) + return + } + this.$toast.success(resp.msg || "地址删除成功") + this.closeHistoryLayer(this.historyLayerNames.deleteConfirm, () => { + this.selectUserAddress() + }) + }).catch(() => { + this.$toast.fail("地址删除失败,请稍后重试") + }).finally(() => { + this.addressDeleteLoading = false + }) + } + }, + created() { + this.subscribeHistoryLayers() + this.selectUserAddress() + }, + beforeDestroy() { + if (typeof this.historyLayerUnsubscribe === "function") this.historyLayerUnsubscribe() + }, + style: /*language=CSS*/ ` + .welfare-address-manager { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + overflow: hidden; + flex-direction: column; + background: #f3f7fc; + } + /deep/ .address-list-header { flex-shrink: 0; } + /deep/ .address-list-header .van-nav-bar { z-index: 3; } + /deep/ .address-list-header .van-nav-bar__title, + /deep/ .address-edit-page .van-nav-bar__title { color: #171d29; font-size: 16px; } + /deep/ .address-list-header .van-nav-bar .van-icon, + /deep/ .address-list-header .van-nav-bar__text, + /deep/ .address-edit-page .van-nav-bar .van-icon, + /deep/ .address-edit-page .van-nav-bar__text { color: #1989fa; } + /deep/ .address-list-scroll { + min-height: 0; + padding: 18px 14px calc(70px + env(safe-area-inset-bottom)); + flex: 1; + overflow-y: auto; + box-sizing: border-box; + -webkit-overflow-scrolling: touch; + } + /deep/ .address-list-loading { display: flex; min-height: 260px; align-items: center; justify-content: center; color: #8c98aa; } + /deep/ .address-swipe-row { + position: relative; + margin-bottom: 14px; + overflow: hidden; + border-radius: 18px; + background: #d94b58; + box-shadow: 0 8px 22px rgba(49, 83, 126, .10); + } + /deep/ .address-swipe-delete { + position: absolute; + top: 0; + right: 0; + bottom: 0; + width: 78px; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + border: 0; + outline: none; + background: #d94b58; + color: #fff; + font-size: 14px; + /* 删除按钮仅在卡片左滑后显示,避免圆角抗锯齿混入红色背景。 */ + visibility: hidden; + pointer-events: none; + } + /deep/ .address-swipe-row.is-swipe-active .address-swipe-delete { + visibility: visible; + pointer-events: auto; + } + /deep/ .address-swipe-delete .van-icon { margin-bottom: 5px; font-size: 21px; } + /deep/ .address-card { + position: relative; + z-index: 2; + padding: 18px 16px 20px; + border: 1px solid transparent; + border-radius: 18px; + background: #fff; + box-sizing: border-box; + transition: transform .22s ease; + touch-action: pan-y; + } + /deep/ .address-card.is-select-mode { border-color: #fff; } + /deep/ .address-card.is-selected { border-color: rgba(25, 137, 250, .32); box-shadow: inset 3px 0 0 #1989fa; } + /deep/ .address-card.is-dragging { transition: none; } + /deep/ .address-card__header, + /deep/ .address-card__footer { display: flex; align-items: center; justify-content: space-between; column-gap: 12px; } + /deep/ .address-card__region-wrap, + /deep/ .address-card__contact { min-width: 0; display: flex; flex: 1; align-items: center; } + /deep/ .address-card__contact { overflow: visible; flex-wrap: wrap; row-gap: 8px; } + /deep/ .address-card__location { + width: 44px; + height: 44px; + margin-right: 10px; + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + border-radius: 50%; + background: #e7f1fb; + color: #1989fa; + font-size: 24px; + } + /deep/ .address-card__region { min-width: 0; overflow-wrap: anywhere; color: #7f8a99; font-size: 15px; line-height: 23px; } + /deep/ .address-card__default { + height: 28px; + padding: 0 11px; + display: flex; + flex-shrink: 0; + align-items: center; + border-radius: 15px; + background: #1989fa; + color: #fff; + font-size: 13px; + line-height: 28px; + box-shadow: 0 4px 10px rgba(25, 137, 250, .18); + } + /deep/ .address-card__default .van-icon { margin-right: 5px; font-size: 16px; } + /deep/ .address-card__detail { margin: 16px 0 0 54px; overflow-wrap: anywhere; color: #171d29; font-size: 18px; font-weight: 700; line-height: 27px; } + /deep/ .address-card__footer { min-height: 28px; margin-top: 22px; } + /deep/ .address-card__contact-item { min-width: 0; max-width: 100%; display: flex; flex-shrink: 0; align-items: center; color: #252b36; font-size: 15px; line-height: 22px; } + /deep/ .address-card__contact-item .van-icon { margin-right: 8px; flex-shrink: 0; color: #8c98aa; font-size: 18px; } + /deep/ .address-card__divider { width: 1px; height: 18px; margin: 0 14px; flex-shrink: 0; background: #d9dee7; } + /deep/ .address-card__edit { padding: 4px 0 4px 8px; display: flex; flex-shrink: 0; align-items: center; border: 0; outline: none; background: transparent; color: #1989fa; font-size: 15px; } + /deep/ .address-card__edit .van-icon { margin-right: 5px; font-size: 18px; } + /deep/ .address-empty { display: flex; min-height: 300px; padding: 28px 18px; align-items: center; justify-content: flex-start; flex-direction: column; box-sizing: border-box; text-align: center; } + /deep/ .address-empty img { display: block; width: 86%; max-width: 300px; height: auto; object-fit: contain; } + /deep/ .address-empty__title { margin-top: -8px; color: #50627a; font-size: 15px; font-weight: 500; } + /deep/ .address-empty__hint { margin-top: 6px; color: #9aa7b8; font-size: 12px; } + /deep/ .address-add-button { + position: absolute; + left: 50%; + bottom: calc(12px + env(safe-area-inset-bottom)); + z-index: 30; + width: calc(100% - 32px); + height: 46px; + padding: 0 16px; + display: flex; + align-items: center; + justify-content: center; + appearance: none; + -webkit-appearance: none; + border: 0; + border-radius: 23px; + outline: none; + color: #fff; + background: #1989fa; + box-shadow: none; + font-family: inherit; + font-size: 16px; + font-weight: 500; + transform: translateX(-50%); + } + /deep/ .address-add-button:active { opacity: .65; background: #1989fa; } + /deep/ .address-add-button .van-icon { margin-right: 6px; font-size: 18px; } + /deep/ .address-edit-popup, + /deep/ .address-edit-page { background: #f3f7fc; } + /deep/ .address-edit-page { position: relative; height: 100%; display: flex; overflow: hidden; flex-direction: column; } + /deep/ .address-edit-scroll { min-height: 0; padding: 22px 16px calc(76px + env(safe-area-inset-bottom)); flex: 1; overflow-y: auto; box-sizing: border-box; -webkit-overflow-scrolling: touch; } + /deep/ .address-recognition-card { margin-bottom: 16px; padding: 18px 16px 14px; overflow: hidden; border-radius: 18px; background: #fff; box-shadow: 0 8px 22px rgba(49, 83, 126, .10); } + /deep/ .address-recognition-card .van-cell { padding: 0; background: transparent; } + /deep/ .address-recognition-card .van-field__control { min-height: 96px; color: #202938; font-size: 15px; line-height: 24px; } + /deep/ .address-recognition-card .van-field__control::placeholder { color: #7d7d7d; opacity: 1; } + /deep/ .address-recognition-card__footer { margin-top: 12px; display: flex; justify-content: flex-end; } + /deep/ .address-recognition-button { width: 70px; height: 32px; border-color: #1989fa; background: #1989fa; font-size: 14px; font-weight: 500; } + /deep/ .address-form-card { overflow: hidden; border-radius: 18px; background: #fff; box-shadow: 0 8px 22px rgba(49, 83, 126, .10); } + /deep/ .address-form-card .van-cell { min-height: 68px; padding: 17px 18px; align-items: center; } + /deep/ .address-form-card .van-cell::after { right: 18px; left: 18px; border-color: #edf0f5; } + /deep/ .address-form-card .van-field__left-icon { margin-right: 12px; } + /deep/ .address-form-card .van-field__left-icon .van-icon, + /deep/ .address-default-title .van-icon { color: #1989fa; font-size: 22px; } + /deep/ .address-form-card .van-field__label { width: 72px; color: #202938; font-size: 15px; font-weight: 500; } + /deep/ .address-form-card .address-form-field.van-cell { min-height: 88px; padding: 15px 18px 13px; align-items: stretch; flex-direction: column; } + /deep/ .address-form-card .address-form-field .van-field__label { width: auto; margin: 0 0 8px; color: #8c98aa; font-weight: 400; line-height: 20px; } + /deep/ .address-form-card .address-form-field .van-cell__value { width: 100%; text-align: left; } + /deep/ .address-form-card .address-form-field .van-field__body { min-height: 24px; } + /deep/ .address-form-card .address-form-field .van-field__control { text-align: left; } + /deep/ .address-default-title { display: flex; align-items: center; color: #202938; font-size: 15px; font-weight: 500; } + /deep/ .address-default-title .van-icon { margin-right: 12px; } + /deep/ .address-edit-footer { position: absolute; right: 0; bottom: 0; left: 0; z-index: 30; padding: 0 16px calc(12px + env(safe-area-inset-bottom)); background: transparent; } + /deep/ .address-save-button { width: 100%; height: 46px; margin: 0; border-color: #1989fa; background: #1989fa; font-size: 16px; font-weight: 500; } + /deep/ .address-area-popup .van-picker__confirm { color: #1989fa; } + /deep/ .address-delete-popup { width: calc(100% - 64px); max-width: 340px; overflow: hidden; border-radius: 16px; background: #fff; } + /deep/ .address-delete-dialog { padding: 24px 20px 0; text-align: center; } + /deep/ .address-delete-dialog__title { color: #202938; font-size: 18px; font-weight: 600; } + /deep/ .address-delete-dialog__message { margin-top: 12px; color: #7d899b; font-size: 14px; line-height: 22px; } + /deep/ .address-delete-dialog__actions { display: flex; margin: 24px -20px 0; border-top: 1px solid #edf0f5; } + /deep/ .address-delete-dialog__button { height: 50px; flex: 1; border: 0; background: #fff; font-size: 16px; } + /deep/ .address-delete-dialog__button + .address-delete-dialog__button { border-left: 1px solid #edf0f5; } + /deep/ .address-delete-dialog__button.is-cancel { color: #596779; } + /deep/ .address-delete-dialog__button.is-confirm { color: #d94b58; font-weight: 500; } + /deep/ .address-delete-dialog__button:disabled { opacity: .55; } + + /* 地址管理页和福利选择页共用同一套紧凑、扁平地址列表视觉规范。 */ + .welfare-address-manager.address-size-compact { + font-size: 12px; + } + .welfare-address-manager.address-size-compact /deep/ .address-list-header .van-nav-bar, + .welfare-address-manager.address-size-compact /deep/ .address-edit-page .van-nav-bar { + background-color: #fff; + } + .welfare-address-manager.address-size-compact /deep/ .address-list-header .van-nav-bar__title, + .welfare-address-manager.address-size-compact /deep/ .address-edit-page .van-nav-bar__title { + color: #1f2937; + font-size: 16px; + } + .welfare-address-manager.address-size-compact /deep/ .address-list-header .van-nav-bar .van-icon, + .welfare-address-manager.address-size-compact /deep/ .address-list-header .van-nav-bar__text, + .welfare-address-manager.address-size-compact /deep/ .address-edit-page .van-nav-bar .van-icon, + .welfare-address-manager.address-size-compact /deep/ .address-edit-page .van-nav-bar__text { + color: #1989fa; + } + .welfare-address-manager.address-size-compact /deep/ .address-list-header .van-nav-bar__left, + .welfare-address-manager.address-size-compact /deep/ .address-edit-page .van-nav-bar__left { + font-size: 14px; + } + .welfare-address-manager.address-size-compact /deep/ .address-list-header .van-nav-bar__arrow, + .welfare-address-manager.address-size-compact /deep/ .address-edit-page .van-nav-bar__arrow { + font-size: 16px; + } + .welfare-address-manager.address-size-compact /deep/ .address-list-loading .van-loading__spinner { + width: 22px !important; + height: 22px !important; + } + .welfare-address-manager.address-size-compact /deep/ .address-list-loading .van-loading__text, + .welfare-address-manager.address-size-compact /deep/ .address-swipe-delete, + .welfare-address-manager.address-size-compact /deep/ .address-delete-dialog__message { + font-size: 12px; + } + .welfare-address-manager.address-size-compact /deep/ .address-swipe-delete .van-icon { + font-size: 19px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card__location { + font-size: 22px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card__region, + .welfare-address-manager.address-size-compact /deep/ .address-card__contact-item, + .welfare-address-manager.address-size-compact /deep/ .address-card__edit, + .welfare-address-manager.address-size-compact /deep/ .address-empty__title, + .welfare-address-manager.address-size-compact /deep/ .address-recognition-card .van-field__control, + .welfare-address-manager.address-size-compact /deep/ .address-recognition-button, + .welfare-address-manager.address-size-compact /deep/ .address-form-card .van-field__label, + .welfare-address-manager.address-size-compact /deep/ .address-default-title { + font-size: 13px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card__default { + font-size: 11px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card__default .van-icon { + font-size: 14px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card__detail, + .welfare-address-manager.address-size-compact /deep/ .address-delete-dialog__title { + font-size: 16px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card__contact-item .van-icon, + .welfare-address-manager.address-size-compact /deep/ .address-card__edit .van-icon, + .welfare-address-manager.address-size-compact /deep/ .address-add-button .van-icon { + font-size: 16px; + } + .welfare-address-manager.address-size-compact /deep/ .address-empty__hint { + font-size: 10px; + } + .welfare-address-manager.address-size-compact /deep/ .address-add-button, + .welfare-address-manager.address-size-compact /deep/ .address-save-button, + .welfare-address-manager.address-size-compact /deep/ .address-delete-dialog__button, + .welfare-address-manager.address-size-compact /deep/ .address-area-popup .van-picker-column, + .welfare-address-manager.address-size-compact /deep/ .address-area-popup .van-picker__title { + font-size: 14px; + } + .welfare-address-manager.address-size-compact /deep/ .address-form-card .van-cell, + .welfare-address-manager.address-size-compact /deep/ .address-area-popup .van-picker__cancel, + .welfare-address-manager.address-size-compact /deep/ .address-area-popup .van-picker__confirm { + font-size: 12px; + } + .welfare-address-manager.address-size-compact /deep/ .address-form-card .van-field__left-icon .van-icon, + .welfare-address-manager.address-size-compact /deep/ .address-default-title .van-icon { + font-size: 20px; + } + .welfare-address-manager.address-size-compact /deep/ .address-form-card .van-field__right-icon .van-icon { + font-size: 14px; + } + .welfare-address-manager.address-size-compact /deep/ .address-save-button .van-loading__spinner { + width: 18px !important; + height: 18px !important; + } + .welfare-address-manager.address-size-compact /deep/ .address-swipe-row { + margin-bottom: 12px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card { + padding: 16px 16px 18px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card__region { + line-height: 21px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card__detail { + margin-top: 14px; + line-height: 25px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card__footer { + margin-top: 20px; + } + .welfare-address-manager.address-size-compact /deep/ .address-card__contact-item, + .welfare-address-manager.address-size-compact /deep/ .address-delete-dialog__message { + line-height: 20px; + } + .welfare-address-manager.address-size-compact /deep/ .address-recognition-card .van-field__control, + .welfare-address-manager.address-size-compact /deep/ .address-form-card .van-cell { + line-height: 22px; + } + + /* 紧凑列表以独立白色卡片展示三层地址信息和右侧编辑入口。 */ + .welfare-address-manager.address-size-compact /deep/ .address-list-scroll { + padding: 12px 12px calc(70px + env(safe-area-inset-bottom)); + background-color: #f3f7fc; + } + .welfare-address-manager.address-size-compact /deep/ .address-swipe-row { + margin-bottom: 12px; + border-radius: 14px; + /* 静止时保持卡片白底,左滑后仅露出右侧红色删除按钮。 */ + background: #fff; + box-shadow: 0 5px 16px rgba(43, 73, 112, .08); + } + .welfare-address-manager.address-size-compact /deep/ .address-card.is-flat-list { + padding: 18px 16px; + border: 0; + border-radius: 14px; + background: #fff; + box-shadow: none; + } + .welfare-address-manager.address-size-compact /deep/ .address-flat__region { + overflow-wrap: anywhere; + color: #98a1b0; + font-size: 13px; + line-height: 20px; + } + .welfare-address-manager.address-size-compact /deep/ .address-flat__main { + min-width: 0; + margin-top: 8px; + display: flex; + align-items: center; + column-gap: 10px; + } + .welfare-address-manager.address-size-compact /deep/ .address-flat__detail { + min-width: 0; + flex: 1; + overflow-wrap: anywhere; + color: #20242d; + font-size: 16px; + line-height: 24px; + } + .welfare-address-manager.address-size-compact /deep/ .address-flat__edit { + width: 40px; + height: 40px; + padding: 0; + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: center; + border: 0; + outline: none; + background: transparent; + color: #8c94a3; + font-size: 20px; + } + .welfare-address-manager.address-size-compact /deep/ .address-flat__edit:active { + opacity: .65; + } + .welfare-address-manager.address-size-compact /deep/ .address-flat__meta { + min-width: 0; + margin-top: 12px; + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 6px 12px; + color: #7f8794; + font-size: 13px; + line-height: 20px; + } + .welfare-address-manager.address-size-compact /deep/ .address-flat__default { + height: 22px; + padding: 0 7px; + display: inline-flex; + align-items: center; + border-radius: 4px; + background-color: #fff0eb; + color: #f26b4f; + font-size: 11px; + line-height: 22px; + box-sizing: border-box; + } + ` +} diff --git a/src/test/js/h5-template-events.test.cjs b/src/test/js/h5-template-events.test.cjs new file mode 100644 index 0000000..320acb5 --- /dev/null +++ b/src/test/js/h5-template-events.test.cjs @@ -0,0 +1,58 @@ +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); +const root = path.resolve(__dirname, '../../..'); +const Vue = require(path.join(root, 'src/main/resources/static/assets/platform/plugins/vue/vue.js')); +const roots = ['src/main/resources/views/platform/zhghh5', 'src/main/resources/views/layouts', 'src/main/resources/static/components']; + +// 只检查模板事件,排除注释;methods 中绑定了实例的 this 不属于此回归。 +const collectEvents = () => { + const records = []; + const walk = directory => { + for (const entry of fs.readdirSync(directory, {withFileTypes: true})) { + const file = path.join(directory, entry.name); + if (entry.isDirectory()) { walk(file); continue; } + if (!/\.(html|js|vue)$/.test(file)) continue; + const source = new TextDecoder('utf-8', {fatal: true}).decode(fs.readFileSync(file)); + const active = source.replace(//g, text => text.replace(/[^\n\r]/g, ' ')); + for (const match of active.matchAll(/(?:@|v-on:)([\w.:-]+)\s*=\s*(["'])([\s\S]*?)\2/g)) { + records.push({file: path.relative(root, file).replaceAll('\\', '/'), line: source.slice(0, match.index).split('\n').length, attribute: match[0], event: match[1], expression: match[3], start: match.index}); + } + } + }; + roots.forEach(directory => walk(path.join(root, directory))); + return records; +}; + +const run = () => { + const records = collectEvents(); + const unsafe = records.filter(record => /\$set\(this\s*,/.test(record.expression) && !/=>/.test(record.expression)); + assert.deepEqual(unsafe.map(record => record.file + ':' + record.line), [], '内联事件不能把调用时的 this 当作页面实例'); + let checked = 0; + for (const record of records.filter(record => /\$set\(\$data\s*,/.test(record.expression))) { + const setters = [...record.expression.matchAll(/\$set\(\$data\s*,\s*['"]([^'"]+)['"]\s*,\s*(true|false|0|row)\s*\)/g)]; + assert(setters.length > 0, record.attribute); + const row = {id: 'test-row'}; + const data = {row, item: {id: 'test-address'}}; + for (const setter of setters) data[setter[1]] = setter[2] === 'true' ? false : setter[2] === 'false' ? true : null; + const instance = new Vue({data: () => data, methods: {addressClick: () => {}}}); + const compiled = Vue.compile(''); + instance.$options.render = compiled.render; + instance.$options.staticRenderFns = compiled.staticRenderFns; + const listener = instance._render().data.on[record.event]; + // 模拟 Vue 组件事件的无实例调用,防止测试人为绑定 this 掩盖原缺陷。 + listener.apply(null, []); + for (const setter of setters) { + const expected = setter[2] === 'row' ? row : JSON.parse(setter[2]); + assert.equal(instance[setter[1]], expected, record.file + ':' + record.line); + } + instance.$destroy(); + checked++; + } + const activity = fs.readFileSync(path.join(root, 'src/main/resources/views/platform/zhghh5/activity/trainSignUp/apply/index.html'), 'utf8'); + assert.match(activity, /title="活动介绍"[^>]*@click-left="historyBack"/, '活动介绍返回必须使用统一历史栈'); + console.log(JSON.stringify({scannedEvents: records.length, checkedDataEvents: checked, unsafeInlineSetters: unsafe.length, activityBack: 'passed'})); +}; + +module.exports = {collectEvents}; +if (require.main === module) run();