TONKIA 4 years ago
parent 428a5d77bb
commit a0302c0f9d
  1. 5
      portal/.editorconfig
  2. 21
      portal/.gitignore
  3. 29
      portal/README.md
  4. 5
      portal/babel.config.js
  5. 11679
      portal/package-lock.json
  6. 57
      portal/package.json
  7. BIN
      portal/public/favicon.ico
  8. BIN
      portal/public/img/default.jpg
  9. BIN
      portal/public/img/skybox/nx.jpg
  10. BIN
      portal/public/img/skybox/ny.jpg
  11. BIN
      portal/public/img/skybox/nz.jpg
  12. BIN
      portal/public/img/skybox/px.jpg
  13. BIN
      portal/public/img/skybox/py.jpg
  14. BIN
      portal/public/img/skybox/pz.jpg
  15. BIN
      portal/public/img/skybox_nature/nx.BMP
  16. BIN
      portal/public/img/skybox_nature/ny.BMP
  17. BIN
      portal/public/img/skybox_nature/nz.BMP
  18. BIN
      portal/public/img/skybox_nature/px.BMP
  19. BIN
      portal/public/img/skybox_nature/py.BMP
  20. BIN
      portal/public/img/skybox_nature/pz.BMP
  21. 20
      portal/public/index.html
  22. 15
      portal/public/js/inflate.min.js
  23. 22
      portal/src/App.vue
  24. 202
      portal/src/components/ThreeStage/index.vue
  25. 4138
      portal/src/components/ThreeStage/plugins/FBXLoader.js
  26. 799
      portal/src/components/ThreeStage/plugins/OBJLoader.js
  27. 1072
      portal/src/components/ThreeStage/plugins/OrbitControls.js
  28. 17
      portal/src/main.js
  29. 4138
      portal/src/plugins/FBXLoader.js
  30. 799
      portal/src/plugins/OBJLoader.js
  31. 7
      portal/src/plugins/vuetify.js
  32. 36
      portal/src/router.js
  33. 16
      portal/src/store.js
  34. 841
      portal/src/views/Create.vue
  35. 514
      portal/src/views/Home.vue
  36. 116
      portal/src/views/Login.vue
  37. 12
      portal/src/views/Refuse.vue
  38. 415
      portal/src/views/Show.vue
  39. 10
      portal/vue.config.js
  40. 13
      server/.idea/compiler.xml
  41. 7
      server/.idea/encodings.xml
  42. 46
      server/.idea/misc.xml
  43. 124
      server/.idea/uiDesigner.xml
  44. 6
      server/.idea/vcs.xml
  45. 1335
      server/.idea/workspace.xml
  46. 219
      server/pom.xml
  47. 101
      server/src/main/java/com/tonkia/v3dmodel/controller/FileController.java
  48. 47
      server/src/main/java/com/tonkia/v3dmodel/controller/HomeController.java
  49. 148
      server/src/main/java/com/tonkia/v3dmodel/controller/SchemeController.java
  50. 97
      server/src/main/java/com/tonkia/v3dmodel/controller/ShowController.java
  51. 93
      server/src/main/java/com/tonkia/v3dmodel/controller/UserController.java
  52. 16
      server/src/main/java/com/tonkia/v3dmodel/mapper/CommentMapper.java
  53. 9
      server/src/main/java/com/tonkia/v3dmodel/mapper/FileMapper.java
  54. 42
      server/src/main/java/com/tonkia/v3dmodel/mapper/SchemeMapper.java
  55. 24
      server/src/main/java/com/tonkia/v3dmodel/mapper/UserMapper.java
  56. 24
      server/src/main/java/com/tonkia/v3dmodel/pojo/CommentInfo.java
  57. 13
      server/src/main/java/com/tonkia/v3dmodel/pojo/CustomerInfo.java
  58. 78
      server/src/main/java/com/tonkia/v3dmodel/pojo/FileInfo.java
  59. 31
      server/src/main/java/com/tonkia/v3dmodel/pojo/FileRely.java
  60. 43
      server/src/main/java/com/tonkia/v3dmodel/pojo/ResponseData.java
  61. 105
      server/src/main/java/com/tonkia/v3dmodel/pojo/SchemeInfo.java
  62. 69
      server/src/main/java/com/tonkia/v3dmodel/pojo/UserInfo.java
  63. 11
      server/src/main/java/com/tonkia/v3dmodel/service/CommentService.java
  64. 25
      server/src/main/java/com/tonkia/v3dmodel/service/FileService.java
  65. 29
      server/src/main/java/com/tonkia/v3dmodel/service/SchemeService.java
  66. 13
      server/src/main/java/com/tonkia/v3dmodel/service/UserService.java
  67. 31
      server/src/main/java/com/tonkia/v3dmodel/service/impl/CommentServiceImpl.java
  68. 196
      server/src/main/java/com/tonkia/v3dmodel/service/impl/FileServiceImpl.java
  69. 101
      server/src/main/java/com/tonkia/v3dmodel/service/impl/SchemeServiceImpl.java
  70. 61
      server/src/main/java/com/tonkia/v3dmodel/service/impl/UserServiceImpl.java
  71. 173
      server/src/main/java/com/tonkia/v3dmodel/utils/FtpUtil.java
  72. 13
      server/src/main/java/com/tonkia/v3dmodel/utils/Test.java
  73. 17
      server/src/main/java/com/tonkia/v3dmodel/utils/ThumbUtil.java
  74. 13
      server/src/main/java/com/tonkia/v3dmodel/utils/UUIDUtil.java
  75. 12
      server/src/main/resources/cfg.properties
  76. 4
      server/src/main/resources/db.properties
  77. 5
      server/src/main/resources/log4j.properties
  78. 131
      server/src/main/resources/springmvc.xml
  79. BIN
      server/src/main/webapp/WEB-INF/lib/commons-codec-1.9.jar
  80. BIN
      server/src/main/webapp/WEB-INF/lib/json.jar
  81. BIN
      server/src/main/webapp/WEB-INF/lib/qcloudsms-1.0.6.jar
  82. BIN
      server/src/main/webapp/WEB-INF/lib/ueditor-1.1.2.jar
  83. 55
      server/src/main/webapp/WEB-INF/web.xml
  84. 1
      server/src/main/webapp/css/app.a0a149c8.css
  85. 1
      server/src/main/webapp/css/chunk-vendors.504cc259.css
  86. BIN
      server/src/main/webapp/favicon.ico
  87. BIN
      server/src/main/webapp/img/default.jpg
  88. BIN
      server/src/main/webapp/img/skybox/nx.jpg
  89. BIN
      server/src/main/webapp/img/skybox/ny.jpg
  90. BIN
      server/src/main/webapp/img/skybox/nz.jpg
  91. BIN
      server/src/main/webapp/img/skybox/px.jpg
  92. BIN
      server/src/main/webapp/img/skybox/py.jpg
  93. BIN
      server/src/main/webapp/img/skybox/pz.jpg
  94. 27
      server/src/main/webapp/index.jsp
  95. 2
      server/src/main/webapp/js/app.f155bb4f.js
  96. 1
      server/src/main/webapp/js/app.f155bb4f.js.map
  97. 27
      server/src/main/webapp/js/chunk-vendors.af4edcc5.js
  98. 1
      server/src/main/webapp/js/chunk-vendors.af4edcc5.js.map
  99. 15
      server/src/main/webapp/js/inflate.min.js
  100. 12
      server/target/classes/cfg.properties
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,5 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

21
portal/.gitignore vendored

@ -0,0 +1,21 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -0,0 +1,29 @@
# v3dmodel
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Run your tests
```
npm run test
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/app'
]
}

11679
portal/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,57 @@
{
"name": "v3dmodel",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^2.6.5",
"qrious": "^4.0.2",
"three": "^0.103.0",
"vue": "^2.6.10",
"vue-resource": "^1.5.1",
"vue-router": "^3.0.3",
"vuetify": "^1.5.5",
"vuex": "^3.0.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.6.0",
"@vue/cli-plugin-eslint": "^3.6.0",
"@vue/cli-service": "^3.6.0",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"stylus": "^0.54.5",
"stylus-loader": "^3.0.1",
"vue-cli-plugin-vuetify": "^0.5.0",
"vue-template-compiler": "^2.5.21",
"vuetify-loader": "^1.0.5"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"@vue/standard"
],
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>V3D</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons">
<script src="./js/inflate.min.js"></script>
</head>
<body>
<noscript>
<strong>We're sorry but v3dmodel doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

@ -0,0 +1,15 @@
/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';var l=void 0,aa=this;function r(c,d){var a=c.split("."),b=aa;!(a[0]in b)&&b.execScript&&b.execScript("var "+a[0]);for(var e;a.length&&(e=a.shift());)!a.length&&d!==l?b[e]=d:b=b[e]?b[e]:b[e]={}};var t="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;function v(c){var d=c.length,a=0,b=Number.POSITIVE_INFINITY,e,f,g,h,k,m,n,p,s,x;for(p=0;p<d;++p)c[p]>a&&(a=c[p]),c[p]<b&&(b=c[p]);e=1<<a;f=new (t?Uint32Array:Array)(e);g=1;h=0;for(k=2;g<=a;){for(p=0;p<d;++p)if(c[p]===g){m=0;n=h;for(s=0;s<g;++s)m=m<<1|n&1,n>>=1;x=g<<16|p;for(s=m;s<e;s+=k)f[s]=x;++h}++g;h<<=1;k<<=1}return[f,a,b]};function w(c,d){this.g=[];this.h=32768;this.d=this.f=this.a=this.l=0;this.input=t?new Uint8Array(c):c;this.m=!1;this.i=y;this.r=!1;if(d||!(d={}))d.index&&(this.a=d.index),d.bufferSize&&(this.h=d.bufferSize),d.bufferType&&(this.i=d.bufferType),d.resize&&(this.r=d.resize);switch(this.i){case A:this.b=32768;this.c=new (t?Uint8Array:Array)(32768+this.h+258);break;case y:this.b=0;this.c=new (t?Uint8Array:Array)(this.h);this.e=this.z;this.n=this.v;this.j=this.w;break;default:throw Error("invalid inflate mode");
}}var A=0,y=1,B={t:A,s:y};
w.prototype.k=function(){for(;!this.m;){var c=C(this,3);c&1&&(this.m=!0);c>>>=1;switch(c){case 0:var d=this.input,a=this.a,b=this.c,e=this.b,f=d.length,g=l,h=l,k=b.length,m=l;this.d=this.f=0;if(a+1>=f)throw Error("invalid uncompressed block header: LEN");g=d[a++]|d[a++]<<8;if(a+1>=f)throw Error("invalid uncompressed block header: NLEN");h=d[a++]|d[a++]<<8;if(g===~h)throw Error("invalid uncompressed block header: length verify");if(a+g>d.length)throw Error("input buffer is broken");switch(this.i){case A:for(;e+
g>b.length;){m=k-e;g-=m;if(t)b.set(d.subarray(a,a+m),e),e+=m,a+=m;else for(;m--;)b[e++]=d[a++];this.b=e;b=this.e();e=this.b}break;case y:for(;e+g>b.length;)b=this.e({p:2});break;default:throw Error("invalid inflate mode");}if(t)b.set(d.subarray(a,a+g),e),e+=g,a+=g;else for(;g--;)b[e++]=d[a++];this.a=a;this.b=e;this.c=b;break;case 1:this.j(ba,ca);break;case 2:for(var n=C(this,5)+257,p=C(this,5)+1,s=C(this,4)+4,x=new (t?Uint8Array:Array)(D.length),S=l,T=l,U=l,u=l,M=l,F=l,z=l,q=l,V=l,q=0;q<s;++q)x[D[q]]=
C(this,3);if(!t){q=s;for(s=x.length;q<s;++q)x[D[q]]=0}S=v(x);u=new (t?Uint8Array:Array)(n+p);q=0;for(V=n+p;q<V;)switch(M=E(this,S),M){case 16:for(z=3+C(this,2);z--;)u[q++]=F;break;case 17:for(z=3+C(this,3);z--;)u[q++]=0;F=0;break;case 18:for(z=11+C(this,7);z--;)u[q++]=0;F=0;break;default:F=u[q++]=M}T=t?v(u.subarray(0,n)):v(u.slice(0,n));U=t?v(u.subarray(n)):v(u.slice(n));this.j(T,U);break;default:throw Error("unknown BTYPE: "+c);}}return this.n()};
var G=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],D=t?new Uint16Array(G):G,H=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],I=t?new Uint16Array(H):H,J=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],K=t?new Uint8Array(J):J,L=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],da=t?new Uint16Array(L):L,ea=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,
13,13],N=t?new Uint8Array(ea):ea,O=new (t?Uint8Array:Array)(288),P,fa;P=0;for(fa=O.length;P<fa;++P)O[P]=143>=P?8:255>=P?9:279>=P?7:8;var ba=v(O),Q=new (t?Uint8Array:Array)(30),R,ga;R=0;for(ga=Q.length;R<ga;++R)Q[R]=5;var ca=v(Q);function C(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h;b<d;){if(f>=g)throw Error("input buffer is broken");a|=e[f++]<<b;b+=8}h=a&(1<<d)-1;c.f=a>>>d;c.d=b-d;c.a=f;return h}
function E(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h=d[0],k=d[1],m,n;b<k&&!(f>=g);)a|=e[f++]<<b,b+=8;m=h[a&(1<<k)-1];n=m>>>16;if(n>b)throw Error("invalid code length: "+n);c.f=a>>n;c.d=b-n;c.a=f;return m&65535}
w.prototype.j=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length-258,f,g,h,k;256!==(f=E(this,c));)if(256>f)b>=e&&(this.b=b,a=this.e(),b=this.b),a[b++]=f;else{g=f-257;k=I[g];0<K[g]&&(k+=C(this,K[g]));f=E(this,d);h=da[f];0<N[f]&&(h+=C(this,N[f]));b>=e&&(this.b=b,a=this.e(),b=this.b);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
w.prototype.w=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length,f,g,h,k;256!==(f=E(this,c));)if(256>f)b>=e&&(a=this.e(),e=a.length),a[b++]=f;else{g=f-257;k=I[g];0<K[g]&&(k+=C(this,K[g]));f=E(this,d);h=da[f];0<N[f]&&(h+=C(this,N[f]));b+k>e&&(a=this.e(),e=a.length);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
w.prototype.e=function(){var c=new (t?Uint8Array:Array)(this.b-32768),d=this.b-32768,a,b,e=this.c;if(t)c.set(e.subarray(32768,c.length));else{a=0;for(b=c.length;a<b;++a)c[a]=e[a+32768]}this.g.push(c);this.l+=c.length;if(t)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];this.b=32768;return e};
w.prototype.z=function(c){var d,a=this.input.length/this.a+1|0,b,e,f,g=this.input,h=this.c;c&&("number"===typeof c.p&&(a=c.p),"number"===typeof c.u&&(a+=c.u));2>a?(b=(g.length-this.a)/this.o[2],f=258*(b/2)|0,e=f<h.length?h.length+f:h.length<<1):e=h.length*a;t?(d=new Uint8Array(e),d.set(h)):d=h;return this.c=d};
w.prototype.n=function(){var c=0,d=this.c,a=this.g,b,e=new (t?Uint8Array:Array)(this.l+(this.b-32768)),f,g,h,k;if(0===a.length)return t?this.c.subarray(32768,this.b):this.c.slice(32768,this.b);f=0;for(g=a.length;f<g;++f){b=a[f];h=0;for(k=b.length;h<k;++h)e[c++]=b[h]}f=32768;for(g=this.b;f<g;++f)e[c++]=d[f];this.g=[];return this.buffer=e};
w.prototype.v=function(){var c,d=this.b;t?this.r?(c=new Uint8Array(d),c.set(this.c.subarray(0,d))):c=this.c.subarray(0,d):(this.c.length>d&&(this.c.length=d),c=this.c);return this.buffer=c};function W(c,d){var a,b;this.input=c;this.a=0;if(d||!(d={}))d.index&&(this.a=d.index),d.verify&&(this.A=d.verify);a=c[this.a++];b=c[this.a++];switch(a&15){case ha:this.method=ha;break;default:throw Error("unsupported compression method");}if(0!==((a<<8)+b)%31)throw Error("invalid fcheck flag:"+((a<<8)+b)%31);if(b&32)throw Error("fdict flag is not supported");this.q=new w(c,{index:this.a,bufferSize:d.bufferSize,bufferType:d.bufferType,resize:d.resize})}
W.prototype.k=function(){var c=this.input,d,a;d=this.q.k();this.a=this.q.a;if(this.A){a=(c[this.a++]<<24|c[this.a++]<<16|c[this.a++]<<8|c[this.a++])>>>0;var b=d;if("string"===typeof b){var e=b.split(""),f,g;f=0;for(g=e.length;f<g;f++)e[f]=(e[f].charCodeAt(0)&255)>>>0;b=e}for(var h=1,k=0,m=b.length,n,p=0;0<m;){n=1024<m?1024:m;m-=n;do h+=b[p++],k+=h;while(--n);h%=65521;k%=65521}if(a!==(k<<16|h)>>>0)throw Error("invalid adler-32 checksum");}return d};var ha=8;r("Zlib.Inflate",W);r("Zlib.Inflate.prototype.decompress",W.prototype.k);var X={ADAPTIVE:B.s,BLOCK:B.t},Y,Z,$,ia;if(Object.keys)Y=Object.keys(X);else for(Z in Y=[],$=0,X)Y[$++]=Z;$=0;for(ia=Y.length;$<ia;++$)Z=Y[$],r("Zlib.Inflate.BufferType."+Z,X[Z]);}).call(this);

@ -0,0 +1,22 @@
<template>
<transition mode="out-in">
<router-view></router-view>
</transition>
</template>
<style>
.v-enter {
opacity: 0;
transform: translateX(300px);
}
.v-leave-to {
opacity: 0;
transform: translateX(-300px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.3s ease;
}
</style>

@ -0,0 +1,202 @@
<template>
<!-- 挂载点 -->
<div style="width: 100%; height: 100%; margin: 0; border: 0; padding: 0;">
<canvas v-if="suportWebGL" ref="stage" style="width: 100%; height: 100%;"></canvas>
<div v-else>
<slot>浏览器不支持WebGL</slot>
</div>
</div>
</template>
<script>
import "./plugins/OrbitControls";
import "./plugins/OBJLoader";
import "./plugins/FBXLoader";
import {
CubeTextureLoader,
Scene,
WebGLRenderer,
PerspectiveCamera,
AmbientLight,
DirectionalLight,
OrbitControls
} from "three";
//WebGL
const suportWebGL = (() => {
try {
var canvas = document.createElement("canvas");
return !!(
window.WebGLRenderingContext &&
(canvas.getContext("webgl") || canvas.getContext("experimental-webgl"))
);
} catch (e) {
return false;
}
})();
export default {
props: ["componentsInfo", "cameraControll"],
data() {
return {
//requestAnimationFrame ID
reqId: null,
//WebGL
suportWebGL,
//
camera: null,
//
scene: new Scene(),
//
control: null
};
},
//DOM
mounted() {
//
this.camera = new PerspectiveCamera(
45,
this.$el.offsetWidth / this.$el.offsetHeight,
0.01,
100000
);
//
this.scene.add(new AmbientLight(0xffffff));
//
this.scene.background = new CubeTextureLoader()
.setPath("/img/skybox/")
.load(["px.jpg", "nx.jpg", "py.jpg", "ny.jpg", "pz.jpg", "nz.jpg"]);
//
this.control = new OrbitControls(this.camera, this.$refs.stage);
//
this.camera.position.y = this.cameraControll.height;
this.control.target.set(0, this.cameraControll.height, 0);
this.control.minDistance = this.cameraControll.distance;
this.control.maxDistance = this.cameraControll.distance;
// this.control.maxPolarAngle = Math.PI / 2;
// this.control.minPolarAngle = Math.PI / 2;
this.control.enablePan = false;
this.control.enableKeys = false;
this.control.update();
//
this.renderer = new WebGLRenderer({
antialias: true,
preserveDrawingBuffer: true,
alpha: true,
canvas: this.$refs.stage
});
this.onResize();
//
this.animate();
//
window.addEventListener("resize", this.onResize, false);
// var grid = new GridHelper(20, 20, 0x0000ff, 0xff0000);
// grid.material.opacity = 0.2;
// grid.material.transparent = true;
// this.scene.add(grid);
},
//
beforeDestroy() {
//
window.removeEventListener("resize", this.onResize, false);
//
cancelAnimationFrame(this.reqId);
},
methods: {
//
onResize() {
let width = this.$el.offsetWidth,
height = this.$el.offsetHeight;
//
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix();
//
this.renderer.setSize(width, height);
this.renderer.setPixelRatio(window.devicePixelRatio || 1);
},
//
animate() {
this.reqId = requestAnimationFrame(this.animate);
this.renderer.render(this.scene, this.camera);
},
updateScene() {
if (this.componentsInfo != null) {
this.componentsInfo.map(item => {
let modelIndex = item.modelSelected;
let textureIndex = item.textureSelected;
let modelObj = null;
if (item.models[modelIndex] != null) {
modelObj = item.models[modelIndex].obj;
}
let textureObj = null;
if (item.textures[textureIndex] != null) {
textureObj = item.textures[textureIndex].obj;
}
if (modelObj != null) {
if (textureObj != null) {
modelObj.traverse(child => {
if (child.isMesh) {
//
textureObj.repeat.set(
this.cameraControll.textureSize,
this.cameraControll.textureSize
);
child.material.map = textureObj;
}
});
}
item.models.map((subItem, index) => {
if (subItem.obj != null) {
// if (subItem.obj.parent == null) {
// this.scene.add(subItem.obj);
// }
this.scene.add(subItem.obj);
if (index == modelIndex) {
subItem.obj.visible = true;
} else {
subItem.obj.visible = false;
}
}
});
}
});
}
},
//File
getCover() {
var dataurl = this.$refs.stage.toDataURL("image/jpeg", 0.2);
var arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], "cover.jpg", { type: mime });
}
},
watch: {
cameraControll: {
handler() {
if (!isNaN(this.cameraControll.height)) {
this.camera.position.y = this.cameraControll.height;
this.control.target.set(0, this.cameraControll.height, 0);
this.control.update();
}
if (!isNaN(this.cameraControll.distance)) {
this.control.minDistance = this.cameraControll.distance;
this.control.maxDistance = this.cameraControll.distance;
this.control.update();
}
if (!isNaN(this.cameraControll.textureSize)) {
this.updateScene();
}
},
deep: true
}
}
};
</script>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,799 @@
import * as THREE from "three";
/**
* @author mrdoob / http://mrdoob.com/
*/
THREE.OBJLoader = ( function () {
// o object_name | g group_name
var object_pattern = /^[og]\s*(.+)?/;
// mtllib file_reference
var material_library_pattern = /^mtllib /;
// usemtl material_name
var material_use_pattern = /^usemtl /;
function ParserState() {
var state = {
objects: [],
object: {},
vertices: [],
normals: [],
colors: [],
uvs: [],
materialLibraries: [],
startObject: function ( name, fromDeclaration ) {
// If the current object (initial from reset) is not from a g/o declaration in the parsed
// file. We need to use it for the first parsed g/o to keep things in sync.
if ( this.object && this.object.fromDeclaration === false ) {
this.object.name = name;
this.object.fromDeclaration = ( fromDeclaration !== false );
return;
}
var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );
if ( this.object && typeof this.object._finalize === 'function' ) {
this.object._finalize( true );
}
this.object = {
name: name || '',
fromDeclaration: ( fromDeclaration !== false ),
geometry: {
vertices: [],
normals: [],
colors: [],
uvs: []
},
materials: [],
smooth: true,
startMaterial: function ( name, libraries ) {
var previous = this._finalize( false );
// New usemtl declaration overwrites an inherited material, except if faces were declared
// after the material, then it must be preserved for proper MultiMaterial continuation.
if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {
this.materials.splice( previous.index, 1 );
}
var material = {
index: this.materials.length,
name: name || '',
mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
smooth: ( previous !== undefined ? previous.smooth : this.smooth ),
groupStart: ( previous !== undefined ? previous.groupEnd : 0 ),
groupEnd: - 1,
groupCount: - 1,
inherited: false,
clone: function ( index ) {
var cloned = {
index: ( typeof index === 'number' ? index : this.index ),
name: this.name,
mtllib: this.mtllib,
smooth: this.smooth,
groupStart: 0,
groupEnd: - 1,
groupCount: - 1,
inherited: false
};
cloned.clone = this.clone.bind( cloned );
return cloned;
}
};
this.materials.push( material );
return material;
},
currentMaterial: function () {
if ( this.materials.length > 0 ) {
return this.materials[ this.materials.length - 1 ];
}
return undefined;
},
_finalize: function ( end ) {
var lastMultiMaterial = this.currentMaterial();
if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) {
lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
lastMultiMaterial.inherited = false;
}
// Ignore objects tail materials if no face declarations followed them before a new o/g started.
if ( end && this.materials.length > 1 ) {
for ( var mi = this.materials.length - 1; mi >= 0; mi -- ) {
if ( this.materials[ mi ].groupCount <= 0 ) {
this.materials.splice( mi, 1 );
}
}
}
// Guarantee at least one empty material, this makes the creation later more straight forward.
if ( end && this.materials.length === 0 ) {
this.materials.push( {
name: '',
smooth: this.smooth
} );
}
return lastMultiMaterial;
}
};
// Inherit previous objects material.
// Spec tells us that a declared material must be set to all objects until a new material is declared.
// If a usemtl declaration is encountered while this new object is being parsed, it will
// overwrite the inherited material. Exception being that there was already face declarations
// to the inherited material, then it will be preserved for proper MultiMaterial continuation.
if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) {
var declared = previousMaterial.clone( 0 );
declared.inherited = true;
this.object.materials.push( declared );
}
this.objects.push( this.object );
},
finalize: function () {
if ( this.object && typeof this.object._finalize === 'function' ) {
this.object._finalize( true );
}
},
parseVertexIndex: function ( value, len ) {
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
},
parseNormalIndex: function ( value, len ) {
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
},
parseUVIndex: function ( value, len ) {
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
},
addVertex: function ( a, b, c ) {
var src = this.vertices;
var dst = this.object.geometry.vertices;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
},
addVertexPoint: function ( a ) {
var src = this.vertices;
var dst = this.object.geometry.vertices;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
},
addVertexLine: function ( a ) {
var src = this.vertices;
var dst = this.object.geometry.vertices;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
},
addNormal: function ( a, b, c ) {
var src = this.normals;
var dst = this.object.geometry.normals;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
},
addColor: function ( a, b, c ) {
var src = this.colors;
var dst = this.object.geometry.colors;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
},
addUV: function ( a, b, c ) {
var src = this.uvs;
var dst = this.object.geometry.uvs;
dst.push( src[ a + 0 ], src[ a + 1 ] );
dst.push( src[ b + 0 ], src[ b + 1 ] );
dst.push( src[ c + 0 ], src[ c + 1 ] );
},
addUVLine: function ( a ) {
var src = this.uvs;
var dst = this.object.geometry.uvs;
dst.push( src[ a + 0 ], src[ a + 1 ] );
},
addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) {
var vLen = this.vertices.length;
var ia = this.parseVertexIndex( a, vLen );
var ib = this.parseVertexIndex( b, vLen );
var ic = this.parseVertexIndex( c, vLen );
this.addVertex( ia, ib, ic );
if ( ua !== undefined && ua !== '' ) {
var uvLen = this.uvs.length;
ia = this.parseUVIndex( ua, uvLen );
ib = this.parseUVIndex( ub, uvLen );
ic = this.parseUVIndex( uc, uvLen );
this.addUV( ia, ib, ic );
}
if ( na !== undefined && na !== '' ) {
// Normals are many times the same. If so, skip function call and parseInt.
var nLen = this.normals.length;
ia = this.parseNormalIndex( na, nLen );
ib = na === nb ? ia : this.parseNormalIndex( nb, nLen );
ic = na === nc ? ia : this.parseNormalIndex( nc, nLen );
this.addNormal( ia, ib, ic );
}
if ( this.colors.length > 0 ) {
this.addColor( ia, ib, ic );
}
},
addPointGeometry: function ( vertices ) {
this.object.geometry.type = 'Points';
var vLen = this.vertices.length;
for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
this.addVertexPoint( this.parseVertexIndex( vertices[ vi ], vLen ) );
}
},
addLineGeometry: function ( vertices, uvs ) {
this.object.geometry.type = 'Line';
var vLen = this.vertices.length;
var uvLen = this.uvs.length;
for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
}
for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
}
}
};
state.startObject( '', false );
return state;
}
//
function OBJLoader( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
this.materials = null;
}
OBJLoader.prototype = {
constructor: OBJLoader,
load: function ( url, onLoad, onProgress, onError ) {
var scope = this;
var loader = new THREE.FileLoader( scope.manager );
loader.setPath( this.path );
loader.load( url, function ( text ) {
onLoad( scope.parse( text ) );
}, onProgress, onError );
},
setPath: function ( value ) {
this.path = value;
return this;
},
setMaterials: function ( materials ) {
this.materials = materials;
return this;
},
parse: function ( text ) {
console.time( 'OBJLoader' );
var state = new ParserState();
if ( text.indexOf( '\r\n' ) !== - 1 ) {
// This is faster than String.split with regex that splits on both
text = text.replace( /\r\n/g, '\n' );
}
if ( text.indexOf( '\\\n' ) !== - 1 ) {
// join lines separated by a line continuation character (\)
text = text.replace( /\\\n/g, '' );
}
var lines = text.split( '\n' );
var line = '', lineFirstChar = '';
var lineLength = 0;
var result = [];
// Faster to just trim left side of the line. Use if available.
var trimLeft = ( typeof ''.trimLeft === 'function' );
for ( var i = 0, l = lines.length; i < l; i ++ ) {
line = lines[ i ];
line = trimLeft ? line.trimLeft() : line.trim();
lineLength = line.length;
if ( lineLength === 0 ) continue;
lineFirstChar = line.charAt( 0 );
// @todo invoke passed in handler if any
if ( lineFirstChar === '#' ) continue;
if ( lineFirstChar === 'v' ) {
var data = line.split( /\s+/ );
switch ( data[ 0 ] ) {
case 'v':
state.vertices.push(
parseFloat( data[ 1 ] ),
parseFloat( data[ 2 ] ),
parseFloat( data[ 3 ] )
);
if ( data.length === 8 ) {
state.colors.push(
parseFloat( data[ 4 ] ),
parseFloat( data[ 5 ] ),
parseFloat( data[ 6 ] )
);
}
break;
case 'vn':
state.normals.push(
parseFloat( data[ 1 ] ),
parseFloat( data[ 2 ] ),
parseFloat( data[ 3 ] )
);
break;
case 'vt':
state.uvs.push(
parseFloat( data[ 1 ] ),
parseFloat( data[ 2 ] )
);
break;
}
} else if ( lineFirstChar === 'f' ) {
var lineData = line.substr( 1 ).trim();
var vertexData = lineData.split( /\s+/ );
var faceVertices = [];
// Parse the face vertex data into an easy to work with format
for ( var j = 0, jl = vertexData.length; j < jl; j ++ ) {
var vertex = vertexData[ j ];
if ( vertex.length > 0 ) {
var vertexParts = vertex.split( '/' );
faceVertices.push( vertexParts );
}
}
// Draw an edge between the first vertex and all subsequent vertices to form an n-gon
var v1 = faceVertices[ 0 ];
for ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) {
var v2 = faceVertices[ j ];
var v3 = faceVertices[ j + 1 ];
state.addFace(
v1[ 0 ], v2[ 0 ], v3[ 0 ],
v1[ 1 ], v2[ 1 ], v3[ 1 ],
v1[ 2 ], v2[ 2 ], v3[ 2 ]
);
}
} else if ( lineFirstChar === 'l' ) {
var lineParts = line.substring( 1 ).trim().split( " " );
var lineVertices = [], lineUVs = [];
if ( line.indexOf( "/" ) === - 1 ) {
lineVertices = lineParts;
} else {
for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {
var parts = lineParts[ li ].split( "/" );
if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] );
if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] );
}
}
state.addLineGeometry( lineVertices, lineUVs );
} else if ( lineFirstChar === 'p' ) {
var lineData = line.substr( 1 ).trim();
var pointData = lineData.split( " " );
state.addPointGeometry( pointData );
} else if ( ( result = object_pattern.exec( line ) ) !== null ) {
// o object_name
// or
// g group_name
// WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
// var name = result[ 0 ].substr( 1 ).trim();
var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 );
state.startObject( name );
} else if ( material_use_pattern.test( line ) ) {
// material
state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
} else if ( material_library_pattern.test( line ) ) {
// mtl file
state.materialLibraries.push( line.substring( 7 ).trim() );
} else if ( lineFirstChar === 's' ) {
result = line.split( ' ' );
// smooth shading
// @todo Handle files that have varying smooth values for a set of faces inside one geometry,
// but does not define a usemtl for each face set.
// This should be detected and a dummy material created (later MultiMaterial and geometry groups).
// This requires some care to not create extra material on each smooth value for "normal" obj files.
// where explicit usemtl defines geometry groups.
// Example asset: examples/models/obj/cerberus/Cerberus.obj
/*
* http://paulbourke.net/dataformats/obj/
* or
* http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
*
* From chapter "Grouping" Syntax explanation "s group_number":
* "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
* Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
* surfaces, smoothing groups are either turned on or off; there is no difference between values greater
* than 0."
*/
if ( result.length > 1 ) {
var value = result[ 1 ].trim().toLowerCase();
state.object.smooth = ( value !== '0' && value !== 'off' );
} else {
// ZBrush can produce "s" lines #11707
state.object.smooth = true;
}
var material = state.object.currentMaterial();
if ( material ) material.smooth = state.object.smooth;
} else {
// Handle null terminated files without exception
if ( line === '\0' ) continue;
throw new Error( 'THREE.OBJLoader: Unexpected line: "' + line + '"' );
}
}
state.finalize();
var container = new THREE.Group();
container.materialLibraries = [].concat( state.materialLibraries );
for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
var object = state.objects[ i ];
var geometry = object.geometry;
var materials = object.materials;
var isLine = ( geometry.type === 'Line' );
var isPoints = ( geometry.type === 'Points' );
var hasVertexColors = false;
// Skip o/g line declarations that did not follow with any faces
if ( geometry.vertices.length === 0 ) continue;
var buffergeometry = new THREE.BufferGeometry();
buffergeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) );
if ( geometry.normals.length > 0 ) {
buffergeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) );
} else {
buffergeometry.computeVertexNormals();
}
if ( geometry.colors.length > 0 ) {
hasVertexColors = true;
buffergeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) );
}
if ( geometry.uvs.length > 0 ) {
buffergeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) );
}
// Create materials
var createdMaterials = [];
for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
var sourceMaterial = materials[ mi ];
var material = undefined;
if ( this.materials !== null ) {
material = this.materials.create( sourceMaterial.name );
// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
var materialLine = new THREE.LineBasicMaterial();
THREE.Material.prototype.copy.call( materialLine, material );
materialLine.color.copy( material.color );
materialLine.lights = false;
material = materialLine;
} else if ( isPoints && material && ! ( material instanceof THREE.PointsMaterial ) ) {
var materialPoints = new THREE.PointsMaterial( { size: 10, sizeAttenuation: false } );
THREE.Material.prototype.copy.call( materialPoints, material );
materialPoints.color.copy( material.color );
materialPoints.map = material.map;
materialPoints.lights = false;
material = materialPoints;
}
}
if ( ! material ) {
if ( isLine ) {
material = new THREE.LineBasicMaterial();
} else if ( isPoints ) {
material = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } );
} else {
material = new THREE.MeshPhongMaterial();
}
material.name = sourceMaterial.name;
}
material.flatShading = sourceMaterial.smooth ? false : true;
material.vertexColors = hasVertexColors ? THREE.VertexColors : THREE.NoColors;
createdMaterials.push( material );
}
// Create mesh
var mesh;
if ( createdMaterials.length > 1 ) {
for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
var sourceMaterial = materials[ mi ];
buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
}
if ( isLine ) {
mesh = new THREE.LineSegments( buffergeometry, createdMaterials );
} else if ( isPoints ) {
mesh = new THREE.Points( buffergeometry, createdMaterials );
} else {
mesh = new THREE.Mesh( buffergeometry, createdMaterials );
}
} else {
if ( isLine ) {
mesh = new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] );
} else if ( isPoints ) {
mesh = new THREE.Points( buffergeometry, createdMaterials[ 0 ] );
} else {
mesh = new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] );
}
}
mesh.name = object.name;
container.add( mesh );
}
console.timeEnd( 'OBJLoader' );
return container;
}
};
return OBJLoader;
} )();

File diff suppressed because it is too large Load Diff

@ -0,0 +1,17 @@
import Vue from 'vue'
import './plugins/vuetify'
import App from './App.vue'
import router from './router'
import store from './store'
import VueResource from 'vue-resource'
Vue.config.productionTip = false
Vue.use(VueResource)
Vue.http.options.emulateJSON = true;
Vue.http.options.emulateHTTP = true;
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')

File diff suppressed because it is too large Load Diff

@ -0,0 +1,799 @@
import * as THREE from "three";
/**
* @author mrdoob / http://mrdoob.com/
*/
THREE.OBJLoader = ( function () {
// o object_name | g group_name
var object_pattern = /^[og]\s*(.+)?/;
// mtllib file_reference
var material_library_pattern = /^mtllib /;
// usemtl material_name
var material_use_pattern = /^usemtl /;
function ParserState() {
var state = {
objects: [],
object: {},
vertices: [],
normals: [],
colors: [],
uvs: [],
materialLibraries: [],
startObject: function ( name, fromDeclaration ) {
// If the current object (initial from reset) is not from a g/o declaration in the parsed
// file. We need to use it for the first parsed g/o to keep things in sync.
if ( this.object && this.object.fromDeclaration === false ) {
this.object.name = name;
this.object.fromDeclaration = ( fromDeclaration !== false );
return;
}
var previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );
if ( this.object && typeof this.object._finalize === 'function' ) {
this.object._finalize( true );
}
this.object = {
name: name || '',
fromDeclaration: ( fromDeclaration !== false ),
geometry: {
vertices: [],
normals: [],
colors: [],
uvs: []
},
materials: [],
smooth: true,
startMaterial: function ( name, libraries ) {
var previous = this._finalize( false );
// New usemtl declaration overwrites an inherited material, except if faces were declared
// after the material, then it must be preserved for proper MultiMaterial continuation.
if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {
this.materials.splice( previous.index, 1 );
}
var material = {
index: this.materials.length,
name: name || '',
mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
smooth: ( previous !== undefined ? previous.smooth : this.smooth ),
groupStart: ( previous !== undefined ? previous.groupEnd : 0 ),
groupEnd: - 1,
groupCount: - 1,
inherited: false,
clone: function ( index ) {
var cloned = {
index: ( typeof index === 'number' ? index : this.index ),
name: this.name,
mtllib: this.mtllib,
smooth: this.smooth,
groupStart: 0,
groupEnd: - 1,
groupCount: - 1,
inherited: false
};
cloned.clone = this.clone.bind( cloned );
return cloned;
}
};
this.materials.push( material );
return material;
},
currentMaterial: function () {
if ( this.materials.length > 0 ) {
return this.materials[ this.materials.length - 1 ];
}
return undefined;
},
_finalize: function ( end ) {
var lastMultiMaterial = this.currentMaterial();
if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) {
lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
lastMultiMaterial.inherited = false;
}
// Ignore objects tail materials if no face declarations followed them before a new o/g started.
if ( end && this.materials.length > 1 ) {
for ( var mi = this.materials.length - 1; mi >= 0; mi -- ) {
if ( this.materials[ mi ].groupCount <= 0 ) {
this.materials.splice( mi, 1 );
}
}
}
// Guarantee at least one empty material, this makes the creation later more straight forward.
if ( end && this.materials.length === 0 ) {
this.materials.push( {
name: '',
smooth: this.smooth
} );
}
return lastMultiMaterial;
}
};
// Inherit previous objects material.
// Spec tells us that a declared material must be set to all objects until a new material is declared.
// If a usemtl declaration is encountered while this new object is being parsed, it will
// overwrite the inherited material. Exception being that there was already face declarations
// to the inherited material, then it will be preserved for proper MultiMaterial continuation.
if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) {
var declared = previousMaterial.clone( 0 );
declared.inherited = true;
this.object.materials.push( declared );
}
this.objects.push( this.object );
},
finalize: function () {
if ( this.object && typeof this.object._finalize === 'function' ) {
this.object._finalize( true );
}
},
parseVertexIndex: function ( value, len ) {
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
},
parseNormalIndex: function ( value, len ) {
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
},
parseUVIndex: function ( value, len ) {
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
},
addVertex: function ( a, b, c ) {
var src = this.vertices;
var dst = this.object.geometry.vertices;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
},
addVertexPoint: function ( a ) {
var src = this.vertices;
var dst = this.object.geometry.vertices;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
},
addVertexLine: function ( a ) {
var src = this.vertices;
var dst = this.object.geometry.vertices;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
},
addNormal: function ( a, b, c ) {
var src = this.normals;
var dst = this.object.geometry.normals;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
},
addColor: function ( a, b, c ) {
var src = this.colors;
var dst = this.object.geometry.colors;
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
},
addUV: function ( a, b, c ) {
var src = this.uvs;
var dst = this.object.geometry.uvs;
dst.push( src[ a + 0 ], src[ a + 1 ] );
dst.push( src[ b + 0 ], src[ b + 1 ] );
dst.push( src[ c + 0 ], src[ c + 1 ] );
},
addUVLine: function ( a ) {
var src = this.uvs;
var dst = this.object.geometry.uvs;
dst.push( src[ a + 0 ], src[ a + 1 ] );
},
addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) {
var vLen = this.vertices.length;
var ia = this.parseVertexIndex( a, vLen );
var ib = this.parseVertexIndex( b, vLen );
var ic = this.parseVertexIndex( c, vLen );
this.addVertex( ia, ib, ic );
if ( ua !== undefined && ua !== '' ) {
var uvLen = this.uvs.length;
ia = this.parseUVIndex( ua, uvLen );
ib = this.parseUVIndex( ub, uvLen );
ic = this.parseUVIndex( uc, uvLen );
this.addUV( ia, ib, ic );
}
if ( na !== undefined && na !== '' ) {
// Normals are many times the same. If so, skip function call and parseInt.
var nLen = this.normals.length;
ia = this.parseNormalIndex( na, nLen );
ib = na === nb ? ia : this.parseNormalIndex( nb, nLen );
ic = na === nc ? ia : this.parseNormalIndex( nc, nLen );
this.addNormal( ia, ib, ic );
}
if ( this.colors.length > 0 ) {
this.addColor( ia, ib, ic );
}
},
addPointGeometry: function ( vertices ) {
this.object.geometry.type = 'Points';
var vLen = this.vertices.length;
for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
this.addVertexPoint( this.parseVertexIndex( vertices[ vi ], vLen ) );
}
},
addLineGeometry: function ( vertices, uvs ) {
this.object.geometry.type = 'Line';
var vLen = this.vertices.length;
var uvLen = this.uvs.length;
for ( var vi = 0, l = vertices.length; vi < l; vi ++ ) {
this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
}
for ( var uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
}
}
};
state.startObject( '', false );
return state;
}
//
function OBJLoader( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
this.materials = null;
}
OBJLoader.prototype = {
constructor: OBJLoader,
load: function ( url, onLoad, onProgress, onError ) {
var scope = this;
var loader = new THREE.FileLoader( scope.manager );
loader.setPath( this.path );
loader.load( url, function ( text ) {
onLoad( scope.parse( text ) );
}, onProgress, onError );
},
setPath: function ( value ) {
this.path = value;
return this;
},
setMaterials: function ( materials ) {
this.materials = materials;
return this;
},
parse: function ( text ) {
console.time( 'OBJLoader' );
var state = new ParserState();
if ( text.indexOf( '\r\n' ) !== - 1 ) {
// This is faster than String.split with regex that splits on both
text = text.replace( /\r\n/g, '\n' );
}
if ( text.indexOf( '\\\n' ) !== - 1 ) {
// join lines separated by a line continuation character (\)
text = text.replace( /\\\n/g, '' );
}
var lines = text.split( '\n' );
var line = '', lineFirstChar = '';
var lineLength = 0;
var result = [];
// Faster to just trim left side of the line. Use if available.
var trimLeft = ( typeof ''.trimLeft === 'function' );
for ( var i = 0, l = lines.length; i < l; i ++ ) {
line = lines[ i ];
line = trimLeft ? line.trimLeft() : line.trim();
lineLength = line.length;
if ( lineLength === 0 ) continue;
lineFirstChar = line.charAt( 0 );
// @todo invoke passed in handler if any
if ( lineFirstChar === '#' ) continue;
if ( lineFirstChar === 'v' ) {
var data = line.split( /\s+/ );
switch ( data[ 0 ] ) {
case 'v':
state.vertices.push(
parseFloat( data[ 1 ] ),
parseFloat( data[ 2 ] ),
parseFloat( data[ 3 ] )
);
if ( data.length === 8 ) {
state.colors.push(
parseFloat( data[ 4 ] ),
parseFloat( data[ 5 ] ),
parseFloat( data[ 6 ] )
);
}
break;
case 'vn':
state.normals.push(
parseFloat( data[ 1 ] ),
parseFloat( data[ 2 ] ),
parseFloat( data[ 3 ] )
);
break;
case 'vt':
state.uvs.push(
parseFloat( data[ 1 ] ),
parseFloat( data[ 2 ] )
);
break;
}
} else if ( lineFirstChar === 'f' ) {
var lineData = line.substr( 1 ).trim();
var vertexData = lineData.split( /\s+/ );
var faceVertices = [];
// Parse the face vertex data into an easy to work with format
for ( var j = 0, jl = vertexData.length; j < jl; j ++ ) {
var vertex = vertexData[ j ];
if ( vertex.length > 0 ) {
var vertexParts = vertex.split( '/' );
faceVertices.push( vertexParts );
}
}
// Draw an edge between the first vertex and all subsequent vertices to form an n-gon
var v1 = faceVertices[ 0 ];
for ( var j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) {
var v2 = faceVertices[ j ];
var v3 = faceVertices[ j + 1 ];
state.addFace(
v1[ 0 ], v2[ 0 ], v3[ 0 ],
v1[ 1 ], v2[ 1 ], v3[ 1 ],
v1[ 2 ], v2[ 2 ], v3[ 2 ]
);
}
} else if ( lineFirstChar === 'l' ) {
var lineParts = line.substring( 1 ).trim().split( " " );
var lineVertices = [], lineUVs = [];
if ( line.indexOf( "/" ) === - 1 ) {
lineVertices = lineParts;
} else {
for ( var li = 0, llen = lineParts.length; li < llen; li ++ ) {
var parts = lineParts[ li ].split( "/" );
if ( parts[ 0 ] !== "" ) lineVertices.push( parts[ 0 ] );
if ( parts[ 1 ] !== "" ) lineUVs.push( parts[ 1 ] );
}
}
state.addLineGeometry( lineVertices, lineUVs );
} else if ( lineFirstChar === 'p' ) {
var lineData = line.substr( 1 ).trim();
var pointData = lineData.split( " " );
state.addPointGeometry( pointData );
} else if ( ( result = object_pattern.exec( line ) ) !== null ) {
// o object_name
// or
// g group_name
// WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
// var name = result[ 0 ].substr( 1 ).trim();
var name = ( " " + result[ 0 ].substr( 1 ).trim() ).substr( 1 );
state.startObject( name );
} else if ( material_use_pattern.test( line ) ) {
// material
state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
} else if ( material_library_pattern.test( line ) ) {
// mtl file
state.materialLibraries.push( line.substring( 7 ).trim() );
} else if ( lineFirstChar === 's' ) {
result = line.split( ' ' );
// smooth shading
// @todo Handle files that have varying smooth values for a set of faces inside one geometry,
// but does not define a usemtl for each face set.
// This should be detected and a dummy material created (later MultiMaterial and geometry groups).
// This requires some care to not create extra material on each smooth value for "normal" obj files.
// where explicit usemtl defines geometry groups.
// Example asset: examples/models/obj/cerberus/Cerberus.obj
/*
* http://paulbourke.net/dataformats/obj/
* or
* http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
*
* From chapter "Grouping" Syntax explanation "s group_number":
* "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
* Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
* surfaces, smoothing groups are either turned on or off; there is no difference between values greater
* than 0."
*/
if ( result.length > 1 ) {
var value = result[ 1 ].trim().toLowerCase();
state.object.smooth = ( value !== '0' && value !== 'off' );
} else {
// ZBrush can produce "s" lines #11707
state.object.smooth = true;
}
var material = state.object.currentMaterial();
if ( material ) material.smooth = state.object.smooth;
} else {
// Handle null terminated files without exception
if ( line === '\0' ) continue;
throw new Error( 'THREE.OBJLoader: Unexpected line: "' + line + '"' );
}
}
state.finalize();
var container = new THREE.Group();
container.materialLibraries = [].concat( state.materialLibraries );
for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
var object = state.objects[ i ];
var geometry = object.geometry;
var materials = object.materials;
var isLine = ( geometry.type === 'Line' );
var isPoints = ( geometry.type === 'Points' );
var hasVertexColors = false;
// Skip o/g line declarations that did not follow with any faces
if ( geometry.vertices.length === 0 ) continue;
var buffergeometry = new THREE.BufferGeometry();
buffergeometry.addAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) );
if ( geometry.normals.length > 0 ) {
buffergeometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) );
} else {
buffergeometry.computeVertexNormals();
}
if ( geometry.colors.length > 0 ) {
hasVertexColors = true;
buffergeometry.addAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) );
}
if ( geometry.uvs.length > 0 ) {
buffergeometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) );
}
// Create materials
var createdMaterials = [];
for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
var sourceMaterial = materials[ mi ];
var material = undefined;
if ( this.materials !== null ) {
material = this.materials.create( sourceMaterial.name );
// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
var materialLine = new THREE.LineBasicMaterial();
THREE.Material.prototype.copy.call( materialLine, material );
materialLine.color.copy( material.color );
materialLine.lights = false;
material = materialLine;
} else if ( isPoints && material && ! ( material instanceof THREE.PointsMaterial ) ) {
var materialPoints = new THREE.PointsMaterial( { size: 10, sizeAttenuation: false } );
THREE.Material.prototype.copy.call( materialPoints, material );
materialPoints.color.copy( material.color );
materialPoints.map = material.map;
materialPoints.lights = false;
material = materialPoints;
}
}
if ( ! material ) {
if ( isLine ) {
material = new THREE.LineBasicMaterial();
} else if ( isPoints ) {
material = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } );
} else {
material = new THREE.MeshPhongMaterial();
}
material.name = sourceMaterial.name;
}
material.flatShading = sourceMaterial.smooth ? false : true;
material.vertexColors = hasVertexColors ? THREE.VertexColors : THREE.NoColors;
createdMaterials.push( material );
}
// Create mesh
var mesh;
if ( createdMaterials.length > 1 ) {
for ( var mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
var sourceMaterial = materials[ mi ];
buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
}
if ( isLine ) {
mesh = new THREE.LineSegments( buffergeometry, createdMaterials );
} else if ( isPoints ) {
mesh = new THREE.Points( buffergeometry, createdMaterials );
} else {
mesh = new THREE.Mesh( buffergeometry, createdMaterials );
}
} else {
if ( isLine ) {
mesh = new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] );
} else if ( isPoints ) {
mesh = new THREE.Points( buffergeometry, createdMaterials[ 0 ] );
} else {
mesh = new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] );
}
}
mesh.name = object.name;
container.add( mesh );
}
console.timeEnd( 'OBJLoader' );
return container;
}
};
return OBJLoader;
} )();

@ -0,0 +1,7 @@
import Vue from 'vue'
import Vuetify from 'vuetify/lib'
import 'vuetify/src/stylus/app.styl'
Vue.use(Vuetify, {
iconfont: 'md',
})

@ -0,0 +1,36 @@
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import Login from './views/Login'
import Create from './views/Create'
import Show from './views/Show'
import Refuse from './views/Refuse'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
component: Login
},
{
path: '/home',
component: Home
},
{
path: '/create/:sid',
component: Create,
props: true
},
{
path: '/show/:sid',
component: Show,
props: true
},
{
path: '/refuse',
component: Refuse
},
]
})

@ -0,0 +1,16 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
}
})

@ -0,0 +1,841 @@
<template>
<v-app dark id="keep">
<!-- 侧边栏开始 -->
<v-navigation-drawer v-model="mainDrawer" absolute fixed clipped app>
<v-list dense>
<v-layout row align-center>
<v-flex xs6>
<v-subheader>所有部件</v-subheader>
</v-flex>
<v-flex xs6 class="text-xs-right">
<v-btn small flat @click="componentDialog=true">编辑</v-btn>
</v-flex>
</v-layout>
<!-- 部件列表开始 -->
<v-list-group v-for="(item,index) in componentsInfo" :key="index">
<template v-slot:activator>
<v-list-tile>
<v-list-tile-content>
<v-list-tile-title>{{ item.componentName }}</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</template>
<v-list-tile
color="amber lighten-1"
v-for="(subItem,subIndex) in item.models"
:key="subItem.fid"
@click="modelChange(index,subIndex)"
>
<v-list-tile-content>
<v-list-tile-title>
{{ subItem.name }}&nbsp;
<v-icon small v-if="subIndex==item.modelSelected">arrow_left</v-icon>
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-divider/>
<v-container grid-list-sm fluid v-if="item.textures.length>0">
<v-layout row wrap>
<v-flex v-for="(subItem,subIndex) in item.textures" :key="subItem.fid" xs2 d-flex>
<v-card flat tile class="d-flex" @click="textureChange(index,subIndex)">
<v-img :src="subItem.path+'?size=60'" aspect-ratio="1" class="grey lighten-2">
<template v-slot:placeholder>
<v-layout fill-height align-center justify-center ma-0>
<v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
</v-layout>
</template>
</v-img>
</v-card>
</v-flex>
</v-layout>
</v-container>
<v-list-tile @click="componentIndex=index;waitUploadList=[];uploadDrawer = true">
<v-list-tile-action>
<v-icon>cloud_upload</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>上传模型文件</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile @click="componentIndex=index;textureDialog=true">
<v-list-tile-action>
<v-icon>picture_in_picture</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>贴图文件管理</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list-group>
<!-- 部件列表结束 -->
<v-list-tile @click="addComponentDialog=true">
<v-list-tile-action>
<v-icon>add</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>添加新部件</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
<!-- 相机参数 -->
<v-list two-line>
<v-list-tile>
<v-layout row>
<v-flex class="pr-3">
<v-slider
label="相机高度"
v-model="cameraControll.height"
:max="cameraControll.heightMax"
min="0"
></v-slider>
</v-flex>
</v-layout>
</v-list-tile>
<v-list-tile>
<v-layout row>
<v-flex class="pr-3">
<v-slider
label="相机距离"
v-model="cameraControll.distance"
:max="cameraControll.distanceMax"
min="0"
></v-slider>
</v-flex>
</v-layout>
</v-list-tile>
<v-list-tile>
<v-layout row>
<v-flex class="pr-3">
<v-slider
label="贴图缩放"
v-model="cameraControll.textureSize"
max="100"
min="1"
></v-slider>
</v-flex>
</v-layout>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<!-- 侧边栏结束 -->
<!-- 工具栏开始 -->
<v-toolbar dark color="red" app clipped-left>
<v-toolbar-side-icon @click="mainDrawer = !mainDrawer"></v-toolbar-side-icon>
<span class="title ml-3 mr-5">
V3D&nbsp;
<span class="font-weight-light">创建方案</span>
</span>
<v-spacer/>
<v-text-field v-model="name" solo-inverted flat hide-details class="hidden-sm-and-down"></v-text-field>
<v-spacer/>
<v-toolbar-items>
<v-btn icon>
<v-icon @click="settingDialog=true">settings</v-icon>
</v-btn>
<v-btn icon>
<v-icon @click="refresh">refresh</v-icon>
</v-btn>
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<v-btn icon v-on="on" @click="saveScheme">
<v-icon>save</v-icon>
</v-btn>
</template>
<span>保存方案</span>
</v-tooltip>
<v-btn icon @click="exitDialog = true">
<v-icon>exit_to_app</v-icon>
</v-btn>
</v-toolbar-items>
</v-toolbar>
<!-- 工具栏结束 -->
<!-- 诡异的样式问题 -->
<v-content style="height:0px;background-color:#ddd">
<ThreeStage
:components-info="componentsInfo"
:camera-controll="cameraControll"
ref="threeStage"
/>
</v-content>
<!-- 右侧drawer开始 -->
<v-navigation-drawer v-model="uploadDrawer" right temporary fixed>
<input
type="file"
multiple="multiple"
ref="file"
style="display:none"
accept=".fbx, .obj"
@change="fileChange"
>
<v-list>
<v-subheader
v-if="componentsInfo[componentIndex]"
>{{componentsInfo[componentIndex].componentName}} - 待上传文件</v-subheader>
<div v-for="(item,index) in waitUploadList" :key="index">
<v-list-tile>
<v-list-tile-content>
<v-list-tile-title v-text="item.name"></v-list-tile-title>
<v-list-tile-sub-title>{{item.size|fileSize}}</v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-action>
<v-btn icon ripple @click="waitUploadList.splice(index, 1)">
<v-icon color="grey lighten-1">cancel</v-icon>
</v-btn>
</v-list-tile-action>
</v-list-tile>
<v-divider></v-divider>
</div>
<v-list-tile>
<v-list-tile-content>
<v-btn block dark color="blue" @click="$refs.file.click()">
选择文件
<v-icon right dark>folder_open</v-icon>
</v-btn>
</v-list-tile-content>
</v-list-tile>
<v-list-tile>
<v-list-tile-content>
<v-btn block dark color="red" @click="uploadModel">
开始上传
<v-icon right dark>cloud_upload</v-icon>
</v-btn>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<!-- 右侧drawer结束 -->
<!-- 贴图管理 开始 -->
<v-dialog v-model="textureDialog" persistent max-width="600px">
<input
type="file"
multiple="multiple"
ref="textureFile"
style="display:none"
accept=".jpg, .png"
@change="textureFileChange"
>
<v-card light>
<v-card-title>
<span
class="headline"
v-if="componentsInfo[componentIndex]"
>{{componentsInfo[componentIndex].componentName}} - 贴图管理</span>
</v-card-title>
<v-card-text>
<v-container grid-list-sm fluid v-if="componentsInfo[componentIndex]">
<v-layout row wrap>
<v-flex
v-for="(item,index) in componentsInfo[componentIndex].textures"
:key="item.name"
xs1
d-flex
@click="delTexture(componentIndex,index)"
>
<v-card flat tile class="d-flex elevation-1">
<v-img :src="item.path+'?size=40'" aspect-ratio="1" class="grey lighten-2">
<template v-slot:placeholder>
<v-layout fill-height align-center justify-center ma-0>
<v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
</v-layout>
</template>
</v-img>
</v-card>
</v-flex>
</v-layout>
</v-container>
<small style="display:block;text-align:right;color:#aaa" class="pr-4">*单击可删除贴图</small>
</v-card-text>
<v-card-actions>
<v-btn color="blue" flat @click="$refs.textureFile.click()">添加贴图</v-btn>
<v-spacer></v-spacer>
<v-btn color="red" flat @click="textureDialog = false">确定</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 贴图管理 结束 -->
<!-- 部件管理 开始 -->
<v-dialog v-model="componentDialog" max-width="600px">
<v-card light>
<v-card-text>
<v-tabs v-model="tabActive" color="red" dark slider-color="yellow">
<v-tab v-for="(item,index) in componentsInfo" :key="index" ripple>{{item.componentName}}</v-tab>
<v-tab-item v-for="(item,index) in componentsInfo" :key="index">
<v-card flat>
<v-card-text>
<v-list>
<div v-for="(subItem,subIndex) in item.models" :key="subItem.fid">
<v-list-tile>
<v-list-tile-content>
<v-text-field
v-model="componentsInfo[index].models[subIndex].name"
single-line
full-width
hide-details
></v-text-field>
</v-list-tile-content>
<v-list-tile-content class="align-end">
<v-btn icon ripple @click="delModel(index, subIndex)">
<v-icon color="grey lighten-1">cancel</v-icon>
</v-btn>
</v-list-tile-content>
</v-list-tile>
<v-divider/>
</div>
</v-list>
</v-card-text>
</v-card>
<div class="text-xs-center">
<v-btn round color="primary" outline @click="delComponent(index)">删除该部件</v-btn>
</div>
</v-tab-item>
</v-tabs>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="red"
flat
@click="componentDialog = false"
item-text="componentName"
item-children="models"
>确定</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 部件管理 结束 -->
<!-- 添加部件模态框 开始-->
<v-dialog v-model="addComponentDialog" width="500">
<v-card>
<v-toolbar dark color="red">
<v-toolbar-title>添加新部件</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon dark @click="addComponentDialog = false">
<v-icon>close</v-icon>
</v-btn>
</v-toolbar>
<v-card-text>
<v-text-field label="部件名称" color="red" v-model="componentName"></v-text-field>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn dark flat @click="addComponent">添加</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 添加部件模态框 结束 -->
<!-- 文件上传进度模态框 开始 -->
<v-dialog v-model="uploadingDialog" persistent width="300">
<v-card color="red" dark>
<v-card-text>
文件上传中
<v-progress-linear indeterminate color="white" class="mb-0"></v-progress-linear>
</v-card-text>
</v-card>
</v-dialog>
<!-- 文件上传进度模态框 结束-->
<!-- 文件加载进度模态框 开始 -->
<v-dialog v-model="downloadingDialog" persistent width="300">
<v-card color="red" dark>
<v-card-text>
文件加载中
<v-progress-linear indeterminate color="white" class="mb-0"></v-progress-linear>
</v-card-text>
</v-card>
</v-dialog>
<!-- 文件加载进度模态框 结束-->
<!-- 退出保存模态框 开始 -->
<v-dialog v-model="exitDialog" width="300">
<v-card>
<v-card-text>是否保存当前修改</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn flat @click="$router.push('/home')">直接退出</v-btn>
<v-btn flat @click="saveScheme();$router.push('/home')">保存退出</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 退出保存模态框 结束 -->
<!-- 设置开始 -->
<v-dialog v-model="settingDialog" fullscreen hide-overlay transition="dialog-bottom-transition">
<v-card light>
<v-toolbar dark color="primary">
<v-btn icon dark @click="settingDialog = false">
<v-icon>close</v-icon>
</v-btn>
<v-toolbar-title>设置</v-toolbar-title>
<v-spacer></v-spacer>
<v-toolbar-items>
<v-btn dark flat @click="saveSetting">确定</v-btn>
</v-toolbar-items>
</v-toolbar>
<v-list three-line subheader>
<v-subheader>相机参数</v-subheader>
<v-list-tile avatar>
<v-list-tile-content>
<v-list-tile-title>相机最大高度</v-list-tile-title>
<v-list-tile-sub-title>
<v-flex shrink style="width: 60px">
<v-text-field
v-model="cameraControll.heightMax"
class="mt-0"
hide-details
single-line
type="number"
></v-text-field>
</v-flex>
</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile avatar>
<v-list-tile-content>
<v-list-tile-title>相机最远距离</v-list-tile-title>
<v-list-tile-sub-title>
<v-flex shrink style="width: 60px">
<v-text-field
v-model="cameraControll.distanceMax"
class="mt-0"
hide-details
single-line
type="number"
></v-text-field>
</v-flex>
</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
<v-divider></v-divider>
<v-subheader>方案分享</v-subheader>
<v-layout wrap class="ma-3">
<v-flex xs12 sm8 class="pr-5">
<v-switch label="开启分享" color="red" v-model="isShared"></v-switch>
<v-text-field label="访问地址" outline readonly :value="shareLink"></v-text-field>
<input :value="shareLink" ref="shareLink" style="display:none">
<input
:value="`<iframe src='${shareLink}' scrolling='no' frameborder='0' width='100%' height='100%'></iframe>`"
ref="iframLink"
style="display:none"
>
<v-switch label="使用密码" color="red" v-model="hasPassword"></v-switch>
<v-text-field
v-model="sharePassword"
label="访问密码"
:type="hasPassword&&showPassword ? 'text' : 'password'"
:disabled="!hasPassword"
:append-icon="hasPassword&&showPassword? 'visibility' : 'visibility_off'"
@click:append="showPassword = !showPassword"
></v-text-field>
</v-flex>
<v-flex xs12 sm4>
<v-layout justify-end fill-height>
<v-flex align-self-end>
<canvas ref="qr"></canvas>
</v-flex>
<v-spacer/>
<v-layout column justify-end class="mb-3">
<a style="text-align:right" class="ma-2">
关于IFrames地址的使用
<v-icon small>help</v-icon>
</a>
<v-btn color="blue" dark @click="copyIframe">iframe地址</v-btn>
<v-btn color="blue" dark @click="copyLink">复制访问地址</v-btn>
<v-btn color="green" dark @click="saveQR">保存二维码</v-btn>
</v-layout>
</v-layout>
</v-flex>
</v-layout>
</v-list>
</v-card>
</v-dialog>
<!-- 设置结束 -->
</v-app>
</template>
<script>
import "../plugins/OBJLoader";
import "../plugins/FBXLoader";
import {
LoadingManager,
TextureLoader,
OBJLoader,
FBXLoader,
DoubleSide
} from "three";
import ThreeStage from "../components/ThreeStage";
import QRious from "qrious";
export default {
components: {
ThreeStage
},
props: ["sid"],
data: () => ({
//tab
tabActive: null,
//drawer
mainDrawer: false,
uploadDrawer: false,
//dialog
addComponentDialog: null,
uploadingDialog: null,
downloadingDialog: null,
exitDialog: null,
textureDialog: null,
settingDialog: null,
componentDialog: null,
//
componentIndex: null,
componentName: "",
waitUploadList: [],
//
name: "",
cameraControll: {
height: 10,
distance: 40,
textureSize:1,
heightMax: 200,
distanceMax: 200
},
componentsInfo: [],
//share
shareLink: "",
isShared: false,
hasPassword: false,
showPassword: false,
sharePassword: ""
}),
watch: {
//dialog退
addComponentDialog() {
this.componentName = "";
}
},
filters: {
fileSize: function(value) {
return (value / 1024 / 1024).toFixed(2) + " MB";
}
},
methods: {
saveSetting() {
let share = 0;
if (this.isShared) {
if (this.hasPassword) {
share = 2;
} else {
share = 1;
}
}
this.$http
.post(
"/scheme/share",
{
sid: this.sid,
share: share,
password: this.sharePassword
},
{}
)
.then(
data => {
console.info(data);
},
error => {
console.info(error);
}
);
this.settingDialog = false;
},
copyLink() {
this.$refs.shareLink.style.display = "inline";
this.$refs.shareLink.select();
document.execCommand("Copy");
this.$refs.shareLink.style.display = "none";
},
copyIframe() {
this.$refs.iframLink.style.display = "inline";
this.$refs.iframLink.select();
document.execCommand("Copy");
this.$refs.iframLink.style.display = "none";
},
saveQR() {
let a = document.createElement("a");
a.href = this.$refs.qr.toDataURL("image/png");
a.download = "qr.png";
let event = document.createEvent("MouseEvents");
event.initEvent("click", true, false);
a.dispatchEvent(event);
},
addComponent() {
let componentName = this.componentName.replace(/\s+/g, "");
if (componentName.length > 0)
this.componentsInfo.push({
componentName,
modelSelected: -1,
textureSelected: -1,
models: [],
textures: []
});
this.addComponentDialog = false;
},
fileChange() {
for (var i = 0, j = this.$refs.file.files.length; i < j; i++) {
this.waitUploadList.push(this.$refs.file.files[i]);
}
//file input
this.$refs.file.value = "";
},
textureFileChange() {
if (this.$refs.textureFile.files.length > 0) {
this.uploadingDialog = true;
var formData = new FormData();
formData.append("sid", this.sid);
for (var i = 0, j = this.$refs.textureFile.files.length; i < j; i++) {
formData.append("files", this.$refs.textureFile.files[i]);
}
this.$http
.post("/file/uploadTexture", formData, {
headers: { "Content-Type": "multipart/form-data" }
})
.then(
data => {
console.info(data);
if (data.body.code == 0) {
data.body.data.uploadReply.map(item => {
this.componentsInfo[this.componentIndex].textures.push(item);
});
}
this.uploadingDialog = false;
},
error => {
console.info(error);
}
);
//file input
this.$refs.textureFile.value = "";
}
},
uploadModel() {
if (this.waitUploadList.length > 0) {
this.uploadDrawer = false;
this.uploadingDialog = true;
var formData = new FormData();
formData.append("sid", this.sid);
this.waitUploadList.map(item => {
formData.append("files", item);
});
this.$http
.post("/file/uploadModel", formData, {
headers: { "Content-Type": "multipart/form-data" }
})
.then(
data => {
console.info(data);
if (data.body.code == 0) {
data.body.data.uploadReply.map(item => {
this.componentsInfo[this.componentIndex].models.push(item);
});
}
this.uploadingDialog = false;
},
error => {
console.info(error);
}
);
}
},
refresh() {
this.$http.get("/scheme/" + this.sid, {}, {}).then(
data => {
console.info(data);
if (data.body.code == 0) {
this.name = data.body.data.name;
this.shareLink = data.body.data.shareLink;
this.sharePassword = data.body.data.password;
var qr = new QRious({
element: this.$refs.qr,
size: 250,
level: "L",
foreground: "#424242",
background: "#fff",
value: this.shareLink
});
switch (data.body.data.share) {
case 0:
this.isShared = false;
this.hasPassword = false;
break;
case 1:
this.isShared = true;
this.hasPassword = false;
break;
case 2:
this.isShared = true;
this.hasPassword = true;
break;
}
let componentsInfo = JSON.parse(data.body.data.data);
let cameraControll = JSON.parse(data.body.data.camera);
if (componentsInfo) this.componentsInfo = componentsInfo;
if (cameraControll) this.cameraControll = cameraControll;
let manager = new LoadingManager(() => {
this.downloadingDialog = false;
});
this.componentsInfo.map((item, index) => {
let modelIndex = item.modelSelected;
let textureIndex = item.textureSelected;
if (item.models[modelIndex] != null) {
this.downloadingDialog = true;
this.modelChange(index, modelIndex, manager);
}
if (item.textures[textureIndex] != null) {
this.downloadingDialog = true;
this.textureChange(index, textureIndex, manager);
}
});
} else if (data.body.code == 2) {
this.$router.push("/");
} else {
this.$router.push("/home");
}
},
error => {
console.info(error);
}
);
},
saveScheme() {
var formData = new FormData();
formData.append("sid", this.sid);
formData.append("name", this.name);
formData.append("file", this.$refs.threeStage.getCover());
//obj
formData.append(
"data",
JSON.stringify(this.componentsInfo, (key, value) => {
if (key == "obj") {
return null;
} else {
return value;
}
})
);
formData.append("camera", JSON.stringify(this.cameraControll));
this.$http
.post("/scheme/save", formData, {
headers: { "Content-Type": "multipart/form-data" }
})
.then(
data => {
console.info(data);
},
error => {
console.info(error);
}
);
},
modelChange(componentIndex, modelIndex, manager) {
if (manager == null) {
this.downloadingDialog = true;
manager = new LoadingManager(() => {
this.downloadingDialog = false;
});
}
let model = this.componentsInfo[componentIndex].models[modelIndex];
if (model.obj == null) {
//obj
if (
model.path
.split(".")
.pop()
.toLowerCase() === "obj"
) {
new OBJLoader(manager).load(
model.path,
//success
obj => {
obj.traverse(child => {
if (child.isMesh) {
child.material.side = DoubleSide;
}
});
model.obj = obj;
this.componentsInfo[componentIndex].modelSelected = modelIndex;
this.$refs.threeStage.updateScene();
}
);
//fbx
} else if (
model.path
.split(".")
.pop()
.toLowerCase() === "fbx"
) {
new FBXLoader(manager).load(
model.path,
obj => {
obj.traverse(child => {
if (child.isMesh) {
child.material.side = DoubleSide;
}
});
model.obj = obj;
this.componentsInfo[componentIndex].modelSelected = modelIndex;
this.$refs.threeStage.updateScene();
},
xhr => {
if (xhr.lengthComputable) {
// console.info((xhr.loaded / xhr.total) * 100);
}
}
);
}
} else {
this.componentsInfo[componentIndex].modelSelected = modelIndex;
this.$refs.threeStage.updateScene();
this.downloadingDialog = false;
}
},
textureChange(componentIndex, textureIndex, manager) {
if (manager == null) {
this.downloadingDialog = true;
manager = new LoadingManager(() => {
this.downloadingDialog = false;
});
}
let texture = this.componentsInfo[componentIndex].textures[textureIndex];
if (texture.obj == null) {
new TextureLoader(manager).load(texture.path, obj => {
texture.obj = obj;
this.componentsInfo[componentIndex].textureSelected = textureIndex;
this.$refs.threeStage.updateScene();
});
} else {
this.componentsInfo[componentIndex].textureSelected = textureIndex;
this.$refs.threeStage.updateScene();
this.downloadingDialog = false;
}
},
delTexture(componentIndex, textureIndex) {
this.componentsInfo[componentIndex].textures.splice(textureIndex, 1);
},
delModel(componentIndex, modelIndex) {
let model = this.componentsInfo[componentIndex].models[modelIndex].obj;
if (model != null) {
model.parent.remove(model);
}
this.componentsInfo[componentIndex].models.splice(modelIndex, 1);
},
delComponent(componentIndex) {
for (let component of this.componentsInfo[componentIndex].models) {
if (component.obj != null) {
component.obj.parent.remove(component.obj);
}
}
this.componentsInfo.splice(componentIndex, 1);
}
},
created() {
this.refresh();
}
};
</script>
<style >
</style>

@ -0,0 +1,514 @@
<template>
<v-app dark id="inspire">
<!-- drawer开始 -->
<v-navigation-drawer v-model="drawer" fixed app>
<v-list class="pa-1">
<v-list-tile avatar>
<v-list-tile-avatar @click="avatarUpload=true">
<img :src="avatar">
</v-list-tile-avatar>
<v-list-tile-content>
<v-list-tile-title v-text="userName"></v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
<v-list class="pt-0" dense>
<v-divider></v-divider>
<v-list-tile @click="userDialog=true">
<v-list-tile-action>
<v-icon>account_box</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>修改用户信息</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile @click>
<v-list-tile-action>
<v-icon>info</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>关于V3D</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-list-tile @click="logout">
<v-list-tile-action>
<v-icon>exit_to_app</v-icon>
</v-list-tile-action>
<v-list-tile-content>
<v-list-tile-title>退出系统</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
<!-- drawer结束 -->
<!-- 工具栏开始 -->
<v-toolbar color="red" dark fixed app>
<v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
<v-toolbar-title>V3D</v-toolbar-title>
<v-spacer/>
<v-text-field
clearable
v-model="keyword"
solo-inverted
flat
hide-details
label="搜索"
prepend-inner-icon="search"
class="hidden-sm-and-down"
></v-text-field>
<v-spacer/>
<v-toolbar-items class="hidden-sm-and-down">
<v-btn flat @click="createDialog=true">
<v-icon>add</v-icon>
</v-btn>
</v-toolbar-items>
</v-toolbar>
<!-- 工具栏结束 -->
<!-- 内容开始 -->
<v-content>
<v-container fluid fill-height v-if="schemeList.length==0">
<v-layout justify-center align-center>
<v-flex text-xs-center class="headline font-weight-light">还没有方案请先创建方案</v-flex>
</v-layout>
</v-container>
<v-container fluid grid-list-md v-else>
<v-layout row wrap>
<v-flex
v-for="(item,index) in schemeList"
:key="item.sid"
xs12
sm6
md3
v-if="keyword==null||item.name.indexOf(keyword)!=-1"
>
<v-card>
<v-img :src="item.cover" height="200px">
<v-container fill-height fluid pa-2>
<v-layout fill-height>
<v-flex xs12 align-end flexbox>
<span class="headline white--text" v-text="item.name"></span>
</v-flex>
</v-layout>
</v-container>
</v-img>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn icon @click="edit(item.sid)">
<v-icon>edit</v-icon>
</v-btn>
<v-btn icon @click="share(index)">
<v-icon>share</v-icon>
</v-btn>
<v-btn icon @click="del(index)">
<v-icon>delete</v-icon>
</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-content>
<!-- 内容结束 -->
<!-- 底部开始 -->
<v-footer color="red" app>
<v-flex py-3 text-xs-center white--text xs12>
<span class="white--text">&copy; 2019 TONKIA V3D</span>
</v-flex>
</v-footer>
<!-- 底部结束 -->
<!-- 创建方案模态框 开始-->
<v-dialog v-model="createDialog" width="500">
<v-card>
<v-toolbar dark color="red">
<v-toolbar-title>创建新方案</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon dark @click="createDialog = false">
<v-icon>close</v-icon>
</v-btn>
</v-toolbar>
<v-card-text>
<v-text-field label="方案名称" color="red" v-model="schemeName"></v-text-field>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn dark flat @click="createScheme">确定</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 创建方案模态框 结束 -->
<!-- 方案分享 开始 -->
<v-dialog v-model="shareDialog" persistent max-width="600px">
<v-card light>
<v-card-title>
<span class="headline">方案分享</span>
</v-card-title>
<v-divider/>
<v-card-text>
<v-container grid-list-md>
<v-layout wrap>
<v-flex xs12>
<v-switch label="开启分享" color="red" v-model="isShared"></v-switch>
<v-text-field label="访问地址" outline readonly :value="shareLink"></v-text-field>
<input :value="shareLink" ref="shareLink" style="display:none">
<input
:value="`<iframe src='${shareLink}' scrolling='no' frameborder='0' width='100%' height='100%'></iframe>`"
ref="iframLink"
style="display:none"
>
</v-flex>
<v-layout class="ma-3">
<canvas ref="qr"></canvas>
<v-spacer/>
<v-layout column justify-end>
<a style="text-align:right" class="ma-2">
关于IFrames地址的使用
<v-icon small>help</v-icon>
</a>
<v-btn color="blue" dark @click="copyIframe">iframe地址</v-btn>
<v-btn color="blue" dark @click="copyLink">复制访问地址</v-btn>
<v-btn color="green" dark @click="saveQR">保存二维码</v-btn>
</v-layout>
</v-layout>
<v-flex xs12>
<v-divider/>
</v-flex>
<v-flex xs12>
<v-switch label="使用密码" color="red" v-model="hasPassword"></v-switch>
<v-text-field
v-model="sharePassword"
label="访问密码"
:type="hasPassword&&showPassword ? 'text' : 'password'"
:disabled="!hasPassword"
:append-icon="hasPassword&&showPassword? 'visibility' : 'visibility_off'"
@click:append="showPassword = !showPassword"
></v-text-field>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
<v-divider/>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" flat @click="shareDialog = false">取消</v-btn>
<v-btn color="blue darken-1" flat @click="saveShare">保存</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 方案分享 结束 -->
<!-- 用户信息修改 开始 -->
<v-dialog v-model="userDialog" persistent max-width="600px">
<v-card light>
<v-card-title>
<span class="headline">用户信息修改</span>
</v-card-title>
<v-divider/>
<v-card-text>
<v-container>
<v-layout row wrap>
<v-flex xs9>
<v-text-field box label="用户名" v-model="newName"></v-text-field>
</v-flex>
<v-flex xs3>
<v-btn large flat color="blue" @click="changeName">修改用户名</v-btn>
</v-flex>
<v-flex xs12>
<v-text-field box label="修改密码" v-model="pwd" type="password"></v-text-field>
</v-flex>
<v-flex xs12>
<v-text-field box label="确认密码" v-model="repwd" type="password"></v-text-field>
</v-flex>
<v-flex xs12>
<v-btn block color="blue" dark @click="changePwd">修改密码</v-btn>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
<v-divider/>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" flat @click="userDialog = false">确认</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 用户信息修改 结束 -->
<!-- 图片上传组件 -->
<avatar-upload
@crop-upload-success="cropUploadSuccess"
field="file"
v-model="avatarUpload"
:width="300"
:height="300"
url="/user/avatar"
img-format="png"
></avatar-upload>
<!-- 图片上传组件 -->
</v-app>
</template>
<script>
import QRious from "qrious";
import avatarUpload from "vue-image-crop-upload";
export default {
components: {
"avatar-upload": avatarUpload
},
data: () => ({
//
schemeList: [],
//
schemeName: "",
keyword: "",
shareLink: "",
isShared: false,
hasPassword: false,
showPassword: false,
sharePassword: "",
shareIndex: 0,
//
avatar: null,
userName: null,
//ui
drawer: null,
createDialog: null,
shareDialog: null,
userDialog: null,
//crop image
avatarUpload: false,
//update userinfo
newName: "",
pwd: "",
repwd: ""
}),
methods: {
changeName() {
this.$http
.post(
"/user/changeInfo",
{
userName: this.newName
},
{}
)
.then(
data => {
console.info(data);
if (data.body.code == 0) {
this.userName = this.newName;
this.newName = "";
}
},
error => {
console.info(error);
}
);
},
changePwd() {
if (this.pwd == this.repwd) {
this.$http
.post(
"/user/changeInfo",
{
password: this.pwd
},
{}
)
.then(
data => {
console.info(data);
if (data.body.code == 0) {
this.pwd = "";
this.repwd = "";
}
},
error => {
console.info(error);
}
);
}
},
cropUploadSuccess(data, field) {
if (data.code == 0) {
this.avatar = data.data.avatar;
}
},
del(index) {
this.$http
.post(
"/scheme/delete",
{
sid: this.schemeList[index].sid
},
{}
)
.then(
data => {
console.info(data);
if (data.body.code == 0) {
this.schemeList.splice(index, 1);
}
},
error => {
console.info(error);
}
);
},
edit(sid) {
this.$router.push("create/" + sid);
},
share(index) {
this.shareIndex = index;
let scheme = this.schemeList[index];
var qr = new QRious({
element: this.$refs.qr,
size: 250,
level: "L",
foreground: "#424242",
background: "#fff",
value: scheme.shareLink
});
this.shareLink = scheme.shareLink;
this.sharePassword = scheme.password;
switch (scheme.share) {
case 0:
this.isShared = false;
this.hasPassword = false;
break;
case 1:
this.isShared = true;
this.hasPassword = false;
break;
case 2:
this.isShared = true;
this.hasPassword = true;
break;
}
this.shareDialog = true;
},
copyLink() {
this.$refs.shareLink.style.display = "inline";
this.$refs.shareLink.select();
document.execCommand("Copy");
this.$refs.shareLink.style.display = "none";
},
copyIframe() {
this.$refs.iframLink.style.display = "inline";
this.$refs.iframLink.select();
document.execCommand("Copy");
this.$refs.iframLink.style.display = "none";
},
saveQR() {
let a = document.createElement("a");
a.href = this.$refs.qr.toDataURL("image/png");
a.download = "qr.png";
let event = document.createEvent("MouseEvents");
event.initEvent("click", true, false);
a.dispatchEvent(event);
},
saveShare() {
let index = this.shareIndex;
let share = 0;
if (this.isShared) {
if (this.hasPassword) {
share = 2;
} else {
share = 1;
}
}
this.schemeList[index].share = share;
this.schemeList[index].password = this.sharePassword;
this.$http
.post(
"/scheme/share",
{
sid: this.schemeList[index].sid,
share: this.schemeList[index].share,
password: this.schemeList[index].password
},
{}
)
.then(
data => {
console.info(data);
},
error => {
console.info(error);
}
);
this.shareDialog = false;
},
createScheme() {
this.$http
.post(
"/scheme/create",
{
name: this.schemeName
},
{}
)
.then(
data => {
console.info(data);
if (data.body.code == 0) {
this.$router.push("create/" + data.body.data.sid);
}
},
error => {
console.info(error);
}
);
},
logout() {
this.$http.get("/user/logout").then(
data => {
console.info(data);
if (data.body.code == 0) {
this.$router.push("/");
}
},
error => {
console.info(error);
}
);
}
},
watch: {
//dialog
createDialog() {
this.schemeName = "";
},
userDialog() {
this.newName = "";
this.pwd = "";
this.repwd = "";
}
},
created() {
this.$http.get("/home/getHomeInfo").then(
data => {
console.info(data);
if (data.body.code == 0) {
//
this.avatar = data.body.data.userInfo.avatar;
this.userName = data.body.data.userInfo.userName;
this.schemeList = data.body.data.schemeList;
} else {
//
this.$router.push("/");
}
},
error => {
console.info(error);
}
);
}
};
</script>

@ -0,0 +1,116 @@
<template>
<v-app dark>
<v-content>
<v-alert
dismissible
v-model="alert"
type="error"
transition="scale-transition"
style="position:absolute;width:100%;margin:0px"
>{{msg}}</v-alert>
<v-container fluid fill-height>
<v-layout align-center justify-center>
<v-flex sm12 md4>
<v-card light class="elevation-12">
<v-toolbar dark color="red">
<v-toolbar-title>用户登录</v-toolbar-title>
<v-spacer></v-spacer>
<!-- 提示的方向 -->
<v-tooltip bottom>
<!-- 这是需要提示的部件任意 -->
<!-- on v-tooltip 传递过来的事件处理方法 -->
<template v-slot:activator="{on}">
<v-btn icon large v-on="on">
<v-icon large>info</v-icon>
</v-btn>
</template>
<!-- 这是默认插槽即提示的内容 -->
<span>关于V3D</span>
</v-tooltip>
</v-toolbar>
<v-card-text>
<v-form>
<v-text-field
prepend-icon="phone"
name="phoneNumber"
label="手机号"
type="tel"
color="red"
v-model="phoneNumber"
mask="###########"
/>
<v-text-field
prepend-icon="lock"
name="password"
label="密码"
type="password"
color="red"
v-model="password"
/>
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn dark color="red" @click="login"> </v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-content>
</v-app>
</template>
<script>
export default {
data: () => ({
alert: false,
msg: "",
phoneNumber: "",
password: ""
}),
methods: {
login() {
this.$http
.post(
"/user/login",
{
phoneNumber: this.phoneNumber,
password: this.password
},
{}
)
.then(
data => {
console.info(data);
if (data.body.code == 0) {
this.$router.push("home");
} else {
this.alert = true;
this.msg = data.body.msg;
}
},
error => {
console.info(error);
}
);
}
},
beforeCreate() {
this.$http.get("/user/hasLogin").then(
data => {
console.info(data);
if (data.body.code == 0) {
this.$router.push("home");
}
},
error => {
console.info(error);
}
);
}
};
</script>
<style>
</style>

@ -0,0 +1,12 @@
<template>
<v-app dark>
<v-content class="body-2 text-xs-center">无法获取数据</v-content>
</v-app>
</template>
<script>
export default {};
</script>
<style>
</style>

@ -0,0 +1,415 @@
<template>
<v-app>
<v-toolbar color="red" dark app clipped-left>
<v-toolbar-side-icon @click="mainDrawer = !mainDrawer"></v-toolbar-side-icon>
<v-toolbar-title>{{name}}</v-toolbar-title>
</v-toolbar>
<v-content style="height:0px;background-color:#ddd">
<ThreeStage
:components-info="componentsInfo"
:camera-controll="cameraControll"
ref="threeStage"
/>
<v-speed-dial
v-model="fab"
bottom
right
direction="top"
transition="slide-y-reverse-transition"
>
<template v-slot:activator>
<v-btn v-model="fab" color="red" dark fab>
<v-icon>add</v-icon>
<v-icon>close</v-icon>
</v-btn>
</template>
<v-btn fab dark small color="blue" @click="pulishDialog=true">
<v-icon>edit</v-icon>
</v-btn>
<v-btn fab dark small color="green" @click="getComment();commentDialog=true">
<v-icon>comment</v-icon>
</v-btn>
</v-speed-dial>
</v-content>
<!-- 文件加载进度模态框 开始 -->
<v-dialog v-model="downloadingDialog" persistent width="300">
<v-card color="red" dark>
<v-card-text>
文件加载中
<v-progress-linear indeterminate color="white" class="mb-0"></v-progress-linear>
</v-card-text>
</v-card>
</v-dialog>
<!-- 文件加载进度模态框 结束-->
<!-- 密码 开始-->
<v-dialog v-model="passwordDialog" persistent max-width="290">
<v-card>
<v-card-title class="headline">该项目需要密码访问</v-card-title>
<v-card-text>
<v-text-field label="密码" outline v-model="password" type="password"></v-text-field>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="green darken-1" flat @click="customer">确定</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 密码 结束-->
<!-- 发表评论 开始 -->
<v-dialog v-model="pulishDialog" max-width="500px">
<v-card>
<v-card-title>发表评论</v-card-title>
<v-divider/>
<v-card-text>
<v-text-field single-line outline v-model="text"></v-text-field>
</v-card-text>
<v-divider/>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="green darken-1" flat @click="pulish">发表</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- 发表评论 结束 -->
<!-- 评论区 开始 -->
<v-dialog v-model="commentDialog" scrollable max-width="800px">
<v-card>
<v-card-title class="font-weight-bold headline">评论区</v-card-title>
<v-divider></v-divider>
<v-card-text style="height: 300px;">
<v-list two-line>
<div v-for="item in commentList" :key="item.time">
<v-list-tile>
<v-list-tile-content>
<v-list-tile-title>{{ item.text }}</v-list-tile-title>
<v-list-tile-sub-title
class="text--primary text-xs-right"
>{{ item.time|timeFilter }}</v-list-tile-sub-title>
</v-list-tile-content>
</v-list-tile>
<v-divider/>
</div>
</v-list>
</v-card-text>
</v-card>
</v-dialog>
<!-- 评论区 结束 -->
<v-navigation-drawer v-model="mainDrawer" absolute fixed clipped app>
<v-tabs v-model="tab" color="red" dark align-with-title show-arrows>
<v-tabs-slider color="yellow"></v-tabs-slider>
<v-tab v-for="(item,index) in componentsInfo" :key="index" ripple>{{item.componentName}}</v-tab>
</v-tabs>
<v-tabs-items v-model="tab" style="position:absolute;buttom:0px;width:100%">
<v-tab-item v-for="(item,index) in componentsInfo" :key="index">
<v-card flat>
<v-card-text>
<v-list-tile
color="amber lighten-1"
v-for="(subItem,subIndex) in item.models"
:key="subItem.fid"
@click="modelChange(index,subIndex)"
>
<v-list-tile-content>
<v-list-tile-title>
{{ subItem.name }}&nbsp;
<v-icon small v-if="subIndex==item.modelSelected">arrow_left</v-icon>
</v-list-tile-title>
</v-list-tile-content>
</v-list-tile>
<v-divider/>
<v-container grid-list-sm fluid v-if="item.textures.length>0">
<v-layout row wrap>
<v-flex v-for="(subItem,subIndex) in item.textures" :key="subItem.fid" xs2 d-flex>
<v-card flat tile class="d-flex" @click="textureChange(index,subIndex)">
<v-img :src="subItem.path+'?size=60'" aspect-ratio="1" class="grey lighten-2">
<template v-slot:placeholder>
<v-layout fill-height align-center justify-center ma-0>
<v-progress-circular indeterminate color="grey lighten-5"></v-progress-circular>
</v-layout>
</template>
</v-img>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
</v-card>
</v-tab-item>
</v-tabs-items>
</v-navigation-drawer>
</v-app>
</template>
<script>
import "../plugins/OBJLoader";
import "../plugins/FBXLoader";
import {
LoadingManager,
TextureLoader,
OBJLoader,
FBXLoader,
DoubleSide
} from "three";
import ThreeStage from "../components/ThreeStage";
export default {
components: {
ThreeStage
},
props: ["sid"],
data() {
return {
commentList: null,
text: "",
mainDrawer: false,
tab: null,
fab: false,
pulishDialog: null,
commentDialog: null,
downloadingDialog: null,
passwordDialog: null,
password: "",
name: "",
cameraControll: {
height: 10,
distance: 40,
heightMax: 200,
distanceMax: 200
},
componentsInfo: []
};
},
methods: {
getComment() {
this.$http.post("/show/getComment", { sid: this.sid }, {}).then(
data => {
console.info(data);
if (data.body.code == 0) {
this.commentList = data.body.data;
}
},
error => {
console.info(error);
}
);
},
pulish() {
this.$http
.post("/show/comment", { sid: this.sid, text: this.text }, {})
.then(
data => {
console.info(data);
if (data.body.code == 0) {
this.pulishDialog = false;
}
},
error => {
console.info(error);
}
);
},
getSchemeInfo() {
this.$http.get("/scheme/" + this.sid, {}, {}).then(
data => {
console.info(data);
if (data.body.code == 0) {
this.name = data.body.data.name;
let componentsInfo = JSON.parse(data.body.data.data);
let cameraControll = JSON.parse(data.body.data.camera);
if (componentsInfo) this.componentsInfo = componentsInfo;
if (cameraControll) this.cameraControll = cameraControll;
let manager = new LoadingManager(() => {
this.downloadingDialog = false;
});
this.componentsInfo.map((item, index) => {
let modelIndex = item.modelSelected;
let textureIndex = item.textureSelected;
if (item.models[modelIndex] != null) {
this.downloadingDialog = true;
this.modelChange(index, modelIndex, manager);
}
if (item.textures[textureIndex] != null) {
this.downloadingDialog = true;
this.textureChange(index, textureIndex, manager);
}
});
} else if (data.body.code == 2) {
this.$router.push("/");
} else {
this.$router.push("/home");
}
},
error => {
console.info(error);
}
);
},
modelChange(componentIndex, modelIndex, manager) {
if (manager == null) {
this.downloadingDialog = true;
manager = new LoadingManager(() => {
this.downloadingDialog = false;
});
}
let model = this.componentsInfo[componentIndex].models[modelIndex];
if (model.obj == null) {
//obj
if (
model.path
.split(".")
.pop()
.toLowerCase() === "obj"
) {
new OBJLoader(manager).load(
model.path,
//success
obj => {
obj.traverse(child => {
if (child.isMesh) {
child.material.side = DoubleSide;
}
});
model.obj = obj;
this.componentsInfo[componentIndex].modelSelected = modelIndex;
this.$refs.threeStage.updateScene();
}
);
//fbx
} else if (
model.path
.split(".")
.pop()
.toLowerCase() === "fbx"
) {
new FBXLoader(manager).load(
model.path,
obj => {
obj.traverse(child => {
if (child.isMesh) {
child.material.side = DoubleSide;
}
});
model.obj = obj;
this.componentsInfo[componentIndex].modelSelected = modelIndex;
this.$refs.threeStage.updateScene();
},
xhr => {
if (xhr.lengthComputable) {
// console.info((xhr.loaded / xhr.total) * 100);
}
}
);
}
} else {
this.componentsInfo[componentIndex].modelSelected = modelIndex;
this.$refs.threeStage.updateScene();
this.downloadingDialog = false;
}
},
textureChange(componentIndex, textureIndex, manager) {
if (manager == null) {
this.downloadingDialog = true;
manager = new LoadingManager(() => {
this.downloadingDialog = false;
});
}
let texture = this.componentsInfo[componentIndex].textures[textureIndex];
if (texture.obj == null) {
new TextureLoader(manager).load(texture.path, obj => {
texture.obj = obj;
this.componentsInfo[componentIndex].textureSelected = textureIndex;
this.$refs.threeStage.updateScene();
});
} else {
this.componentsInfo[componentIndex].textureSelected = textureIndex;
this.$refs.threeStage.updateScene();
this.downloadingDialog = false;
}
},
customer() {
this.$http
.post(
"/show/customer",
{
sid: this.sid,
password: this.password
},
{}
)
.then(
data => {
console.info(data);
if (data.body.code == 0) {
this.passwordDialog = false;
this.password = "";
this.getSchemeInfo();
} else {
this.password = "";
}
},
error => {
console.info(error);
}
);
}
},
watch: {
pulishDialog() {
this.text = "";
}
},
filters: {
timeFilter: function(value) {
var date = new Date();
date.setTime(value);
var month =
date.getMonth().toString().length > 1
? date.getMonth()
: "0" + date.getMonth();
var day =
date.getDate().toString().length > 1
? date.getDate()
: "0" + date.getDate();
var hour =
date.getHours().toString().length > 1
? date.getHours()
: "0" + date.getHours();
var min =
date.getMinutes().toString().length > 1
? date.getMinutes()
: "0" + date.getMinutes();
return (
date.getFullYear() + "-" + month + "-" + day + " " + hour + ":" + min
);
}
},
created() {
this.$http.get("/show/" + this.sid, {}, {}).then(
data => {
if (data.body.code == 0) {
console.info(data);
let share = data.body.data.share;
if (share == 1) {
this.getSchemeInfo();
} else if (share == 2) {
this.passwordDialog = true;
}else{
this.$router.push("/refuse")
}
}
},
error => {
console.info(error);
}
);
}
};
</script>
<style>
.v-speed-dial {
position: absolute;
}
.v-btn--floating {
position: relative;
}
</style>

@ -0,0 +1,10 @@
module.exports = {
devServer: {
host: "localhost",
port: 8080, // 端口号
https: false, // https:{type:Boolean}
open: true, //配置自动启动浏览器
proxy: 'http://localhost'
},
lintOnSave: false
}

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="v3dmodel" />
</profile>
</annotationProcessing>
</component>
</project>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" native2AsciiForPropertiesFiles="true" addBOMForNewFiles="with NO BOM">
<file url="file://$PROJECT_DIR$" charset="UTF-8" />
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
<expanded-state>
<State />
<State>
<id>Java</id>
</State>
<State>
<id>Probable bugsJava</id>
</State>
<State>
<id>RELAX NG</id>
</State>
<State>
<id>XPath</id>
</State>
<State>
<id>XSLT</id>
</State>
</expanded-state>
<selected-state>
<State>
<id>CSS</id>
</State>
</selected-state>
</profile-state>
</entry>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,219 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tonkia</groupId>
<artifactId>v3dmodel</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>v3dmodel Maven Webapp</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<!--<spring-version>4.3.20.RELEASE</spring-version>-->
<spring-version>5.1.3.RELEASE</spring-version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--jsp-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<!--jstl-->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!--spring framework-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--jsckson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<!--apache commons fileupload-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!--短信-->
<dependency>
<groupId>com.github.qcloudsms</groupId>
<artifactId>qcloudsms</artifactId>
<version>1.0.6</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/qcloudsms-1.0.6.jar</systemPath>
</dependency>
<!--ueditor-->
<dependency>
<groupId>com.baidu</groupId>
<artifactId>ueditor</artifactId>
<version>1.1.2</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/ueditor-1.1.2.jar</systemPath>
</dependency>
<dependency>
<groupId>com.json</groupId>
<artifactId>json</artifactId>
<version>1.1.2</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/json.jar</systemPath>
</dependency>
<dependency>
<groupId>com.commons</groupId>
<artifactId>codec</artifactId>
<version>1.9</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/commons-codec-1.9.jar</systemPath>
</dependency>
<!--ftpclient-->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
<!--shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!--图片压缩缩略图-->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
</dependencies>
<build>
<finalName>v3dmodel</finalName>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<uriEncoding>UTF-8</uriEncoding>
<port>80</port>
<path>/</path>
<url>http://v3d.tonkia.xyz/manager/text</url>
<update>true</update>
<username>tonkia</username>
<password>tonkia</password>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,101 @@
package com.tonkia.v3dmodel.controller;
import com.tonkia.v3dmodel.pojo.*;
import com.tonkia.v3dmodel.service.FileService;
import com.tonkia.v3dmodel.service.SchemeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("file")
public class FileController {
@Autowired
FileService fileService;
@Autowired
SchemeService schemeService;
/**
* 上传模型
*
* @param request
* @param files
* @param sid
* @return
*/
@RequestMapping("uploadModel")
@ResponseBody
public ResponseData uploadModel(HttpServletRequest request, MultipartFile[] files, String sid) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
if (userInfo != null) {
if (schemeService.hasPermission(sid, userInfo)) {
List<FileRely> fileInfoList = fileService.insertModelFile(userInfo, sid, files);
Map data = new HashMap<>();
data.put("uploadReply", fileInfoList);
return new ResponseData(ResponseData.SUCCEED, "文件上传成功", data);
}
return new ResponseData(ResponseData.FAILURE, "该用户没有当前方案权限", null);
}
return new ResponseData(ResponseData.FAILURE_UNLOGIN, "用户未登录", null);
}
/**
* 上传贴图
*
* @param request
* @param files
* @param sid
* @return
*/
@RequestMapping("uploadTexture")
@ResponseBody
public ResponseData uploadTexture(HttpServletRequest request, MultipartFile[] files, String sid) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
if (userInfo != null) {
if (schemeService.hasPermission(sid, userInfo)) {
List<FileRely> fileInfoList = fileService.insertTextureFile(userInfo, sid, files);
Map data = new HashMap<>();
data.put("uploadReply", fileInfoList);
return new ResponseData(ResponseData.SUCCEED, "文件上传成功", data);
}
return new ResponseData(ResponseData.FAILURE, "该用户没有当前方案权限", null);
}
return new ResponseData(ResponseData.FAILURE_UNLOGIN, "用户未登录", null);
}
/**
* 资源请求
*
* @param request
* @param response
* @param type 资源类型
* @param sid 所属方案
* @param fileName 文件名
* @param size 图片压缩的大小
*/
//后缀名的匹配规则
@RequestMapping("download/{type}/{sid}/{fileName:.+}")
public void download(HttpServletRequest request, HttpServletResponse response, @PathVariable("type") String type, @PathVariable("sid") String sid, @PathVariable("fileName") String fileName, Integer size) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
CustomerInfo customerInfo = (CustomerInfo) request.getSession().getAttribute("customerInfo");
fileService.download(userInfo, customerInfo, type, sid, fileName, response, size);
}
@RequestMapping("avatar/{fileName:.+}")
public void avatar(HttpServletRequest request, HttpServletResponse response, @PathVariable("fileName") String fileName) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
if (userInfo != null) {
fileService.avatar(userInfo.getUid(), fileName, response);
}
}
}

@ -0,0 +1,47 @@
package com.tonkia.v3dmodel.controller;
import com.tonkia.v3dmodel.pojo.ResponseData;
import com.tonkia.v3dmodel.pojo.SchemeInfo;
import com.tonkia.v3dmodel.pojo.UserInfo;
import com.tonkia.v3dmodel.service.SchemeService;
import com.tonkia.v3dmodel.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("home")
public class HomeController {
@Autowired
UserService userService;
@Autowired
SchemeService schemeService;
/**
* 主页信息请求
* @param request
* @return
*/
@RequestMapping("getHomeInfo")
@ResponseBody
public ResponseData getHomeInfo(HttpServletRequest request) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
if (userInfo != null) {
UserInfo ui = userService.getHomeUserInfo(userInfo.getUid());
List<SchemeInfo> schemeList = schemeService.getHomeSchemeList(userInfo.getUid());
Map data = new HashMap<>();
data.put("userInfo", ui);
data.put("schemeList", schemeList);
return new ResponseData(ResponseData.SUCCEED, "主页信息获取成功", data);
}
return new ResponseData(ResponseData.FAILURE_UNLOGIN, "用户未登录", null);
}
}

@ -0,0 +1,148 @@
package com.tonkia.v3dmodel.controller;
import com.tonkia.v3dmodel.pojo.CustomerInfo;
import com.tonkia.v3dmodel.pojo.ResponseData;
import com.tonkia.v3dmodel.pojo.SchemeInfo;
import com.tonkia.v3dmodel.pojo.UserInfo;
import com.tonkia.v3dmodel.service.FileService;
import com.tonkia.v3dmodel.service.SchemeService;
import org.apache.http.util.TextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("scheme")
public class SchemeController {
@Autowired
SchemeService schemeService;
@Autowired
FileService fileService;
/**
* 创建一个新的方案
*
* @param request
* @param name
* @return
*/
@RequestMapping("create")
@ResponseBody
public ResponseData create(HttpServletRequest request, String name) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
//对于插入操作为了安全,不能把对象暴露给前端啊,是不是?自己再封装一层,只插入name字段
SchemeInfo schemeInfo = new SchemeInfo();
schemeInfo.setName(name);
if (userInfo != null) {
if (!TextUtils.isEmpty(schemeInfo.getName())) {
String sid = schemeService.insertScheme(schemeInfo, userInfo);
if (sid != null) {
Map data = new HashMap<>();
data.put("sid", sid);
return new ResponseData(ResponseData.SUCCEED, "创建方案成功", data);
}
return new ResponseData(ResponseData.FAILURE, "新建方案失败", null);
}
return new ResponseData(ResponseData.FAILURE, "方案名称不能为空", null);
}
return new ResponseData(ResponseData.FAILURE_UNLOGIN, "用户未登录", null);
}
/**
* 保存方案
*
* @param request
* @param schemeInfo
* @param file
* @return
*/
@RequestMapping("save")
@ResponseBody
public ResponseData save(HttpServletRequest request, SchemeInfo schemeInfo, MultipartFile file) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
if (userInfo != null) {
if (!TextUtils.isEmpty(schemeInfo.getName())) {
String cover = fileService.insertCoverFile(schemeInfo.getSid(), file);
if (cover != null) {
schemeInfo.setCover(cover);
schemeInfo.setUid(userInfo.getUid());
if (schemeService.updateScheme(schemeInfo)) {
return new ResponseData(ResponseData.SUCCEED, "保存方案成功", null);
}
return new ResponseData(ResponseData.FAILURE, "保存方案失败", null);
}
return new ResponseData(ResponseData.FAILURE, "缩略图上传失败", null);
}
return new ResponseData(ResponseData.FAILURE, "方案名称不能为空", null);
}
return new ResponseData(ResponseData.FAILURE_UNLOGIN, "用户未登录", null);
}
/**
* 获取方案
*
* @param request
* @param sid
* @return
*/
@RequestMapping("/{sid}")
@ResponseBody
public ResponseData getSchemeInfo(HttpServletRequest request, @PathVariable("sid") String sid) {
int share = schemeService.getShareBySid(sid);
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
CustomerInfo customerInfo = (CustomerInfo) request.getSession().getAttribute("customerInfo");
if (userInfo != null) {
SchemeInfo schemeInfo = schemeService.getSchemeInfo(userInfo.getUid(), sid);
if (schemeInfo != null) {
return new ResponseData(ResponseData.SUCCEED, "方案数据获取成功", schemeInfo);
}
}
if (share == 1) {
SchemeInfo schemeInfo = schemeService.getSchemeInfo(sid);
if (schemeInfo != null) {
return new ResponseData(ResponseData.SUCCEED, "方案数据获取成功", schemeInfo);
}
} else if (share == 2 && customerInfo != null && customerInfo.getSid().equals(sid)) {
SchemeInfo schemeInfo = schemeService.getSchemeInfo(sid);
if (schemeInfo != null) {
return new ResponseData(ResponseData.SUCCEED, "方案数据获取成功", schemeInfo);
}
}
return new ResponseData(ResponseData.FAILURE, "方案数据获取失败", null);
}
@RequestMapping("/share")
@ResponseBody
public ResponseData share(HttpServletRequest request, SchemeInfo schemeInfo) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
if (userInfo != null) {
schemeInfo.setUid(userInfo.getUid());
if (schemeService.updateShareInfo(schemeInfo)) {
return new ResponseData(ResponseData.SUCCEED, "更新分享数据成功", null);
}
return new ResponseData(ResponseData.FAILURE, "更新分享数据失败", null);
}
return new ResponseData(ResponseData.FAILURE_UNLOGIN, "用户未登录", null);
}
@RequestMapping("/delete")
@ResponseBody
public ResponseData delete(HttpServletRequest request, String sid) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
if (userInfo != null) {
if (schemeService.deleteScheme(userInfo.getUid(), sid)) {
return new ResponseData(ResponseData.SUCCEED, "删除方案成功", null);
}
return new ResponseData(ResponseData.FAILURE, "删除方案失败", null);
}
return new ResponseData(ResponseData.FAILURE_UNLOGIN, "用户未登录", null);
}
}

@ -0,0 +1,97 @@
package com.tonkia.v3dmodel.controller;
import com.tonkia.v3dmodel.pojo.*;
import com.tonkia.v3dmodel.service.CommentService;
import com.tonkia.v3dmodel.service.SchemeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("show")
public class ShowController {
@Autowired
SchemeService schemeService;
@Autowired
CommentService commentService;
@RequestMapping("/{sid}")
@ResponseBody
public ResponseData getShareType(@PathVariable("sid") String sid) {
Integer code = schemeService.getShareBySid(sid);
if (code != null) {
Map data = new HashMap<>();
data.put("share", code);
return new ResponseData(ResponseData.SUCCEED, "获取方案分享类型成功", data);
}
return new ResponseData(ResponseData.FAILURE, "获取方案分享类型失败", null);
}
@RequestMapping("customer")
@ResponseBody
public ResponseData customer(HttpServletRequest request, String sid, String password) {
if (schemeService.getCustomer(sid, password)) {
CustomerInfo customerInfo = new CustomerInfo();
customerInfo.setSid(sid);
request.getSession().setAttribute("customerInfo", customerInfo);
return new ResponseData(ResponseData.SUCCEED, "密码有效", null);
}
return new ResponseData(ResponseData.FAILURE, "验证无效", null);
}
@RequestMapping("getComment")
@ResponseBody
public ResponseData getComment(HttpServletRequest request, String sid) {
int share = schemeService.getShareBySid(sid);
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
CustomerInfo customerInfo = (CustomerInfo) request.getSession().getAttribute("customerInfo");
if (userInfo != null && schemeService.hasPermission(sid, userInfo)) {
List<CommentInfo> list = commentService.getAllComment(sid);
if (list != null) {
return new ResponseData(ResponseData.SUCCEED, "方案评论获取成功", list);
}
}
if (share == 1) {
List<CommentInfo> list = commentService.getAllComment(sid);
if (list != null) {
return new ResponseData(ResponseData.SUCCEED, "方案评论获取成功", list);
}
} else if (share == 2 && customerInfo != null && customerInfo.getSid().equals(sid)) {
List<CommentInfo> list = commentService.getAllComment(sid);
if (list != null) {
return new ResponseData(ResponseData.SUCCEED, "方案评论获取成功", list);
}
}
return new ResponseData(ResponseData.FAILURE, "方案评论获取失败", null);
}
@RequestMapping("comment")
@ResponseBody
public ResponseData comment(HttpServletRequest request, String sid,String text) {
int share = schemeService.getShareBySid(sid);
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
CustomerInfo customerInfo = (CustomerInfo) request.getSession().getAttribute("customerInfo");
if (userInfo != null && schemeService.hasPermission(sid, userInfo)) {
if (commentService.insertComment(sid,text)) {
return new ResponseData(ResponseData.SUCCEED, "方案评论成功", null);
}
}
if (share == 1) {
if (commentService.insertComment(sid,text)) {
return new ResponseData(ResponseData.SUCCEED, "方案评论成功", null);
}
} else if (share == 2 && customerInfo != null && customerInfo.getSid().equals(sid)) {
if (commentService.insertComment(sid,text)) {
return new ResponseData(ResponseData.SUCCEED, "方案评论成功", null);
}
}
return new ResponseData(ResponseData.FAILURE, "方案评论失败", null);
}
}

@ -0,0 +1,93 @@
package com.tonkia.v3dmodel.controller;
import com.tonkia.v3dmodel.pojo.ResponseData;
import com.tonkia.v3dmodel.pojo.UserInfo;
import com.tonkia.v3dmodel.service.FileService;
import com.tonkia.v3dmodel.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("user")
public class UserController {
@Autowired
UserService userService;
@Autowired
FileService fileService;
//验证登录
@RequestMapping("hasLogin")
@ResponseBody
public ResponseData hasLogin(HttpServletRequest request) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
if (userInfo != null) {
return new ResponseData(ResponseData.SUCCEED, "登录成功", null);
}
return new ResponseData(ResponseData.FAILURE_UNLOGIN, "用户未登录", null);
}
//登录请求
@RequestMapping("login")
@ResponseBody
public ResponseData login(HttpServletRequest request, UserInfo userInfo) {
UserInfo ui = userService.getUserInfo(userInfo);
if (ui == null) {
//用户不存在
return new ResponseData(ResponseData.FAILURE, "用户不存在", null);
}
if (!ui.getPassword().equals(userInfo.getPassword())) {
//密码错误
return new ResponseData(ResponseData.FAILURE, "密码错误", null);
}
request.getSession().setAttribute("userInfo", ui);
return new ResponseData(ResponseData.SUCCEED, "登录成功", null);
}
//用户注销
@RequestMapping("logout")
@ResponseBody
public ResponseData logout(HttpServletRequest request) {
request.getSession().setAttribute("userInfo", null);
return new ResponseData(ResponseData.SUCCEED, "注销成功", null);
}
//修改头像
@RequestMapping("avatar")
@ResponseBody
public ResponseData avatar(HttpServletRequest request, MultipartFile file) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
if (userInfo != null) {
String path = fileService.uploadAvatar(userInfo.getUid(), file);
if (userService.updateAvatar(userInfo.getUid(), path)) {
Map data = new HashMap();
data.put("avatar", path);
return new ResponseData(ResponseData.SUCCEED, "头像修改成功", data);
}
return new ResponseData(ResponseData.FAILURE, "头像修改失败", null);
}
return new ResponseData(ResponseData.FAILURE_UNLOGIN, "用户未登录", null);
}
//修改头像
@RequestMapping("changeInfo")
@ResponseBody
public ResponseData changeInfo(HttpServletRequest request, String userName, String password) {
UserInfo userInfo = (UserInfo) request.getSession().getAttribute("userInfo");
if (userInfo != null) {
if (userService.updateInfo(userInfo.getUid(),userName,password)) {
return new ResponseData(ResponseData.SUCCEED, "用户信息修改成功", null);
}
return new ResponseData(ResponseData.FAILURE, "用户信息修改失败", null);
}
return new ResponseData(ResponseData.FAILURE_UNLOGIN, "用户未登录", null);
}
}

@ -0,0 +1,16 @@
package com.tonkia.v3dmodel.mapper;
import com.tonkia.v3dmodel.pojo.CommentInfo;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
public interface CommentMapper {
@Select("select text,time from tb_comment where sid = #{sid} order by time desc")
List<CommentInfo> getAllComment(String sid);
@Insert("insert into tb_comment(text,sid) values (#{text},#{sid})")
boolean insertComment(Map para);
}

@ -0,0 +1,9 @@
package com.tonkia.v3dmodel.mapper;
import com.tonkia.v3dmodel.pojo.FileInfo;
import org.apache.ibatis.annotations.Insert;
public interface FileMapper {
@Insert("insert into tb_file(fid,uid,sid,type,path,name) values(#{fid},#{uid},#{sid},#{type},#{path},#{name})")
boolean insertFile(FileInfo fi);
}

@ -0,0 +1,42 @@
package com.tonkia.v3dmodel.mapper;
import com.tonkia.v3dmodel.pojo.SchemeInfo;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
import java.util.Map;
public interface SchemeMapper {
@Insert("insert into tb_scheme(sid,uid,name,createTime) values(#{sid},#{uid},#{name},#{createTime})")
boolean insertScheme(SchemeInfo schemeInfo);
@Select("select sid,name,cover,share,password from tb_scheme where uid = #{0} and state = 0 order by createTime desc")
List<SchemeInfo> getHomeSchemeList(Integer uid);
@Select("select count(*) from tb_scheme where uid = #{uid} and sid = #{sid}")
int hasPermission(Map para);
@Update("update tb_scheme set name=#{name},cover=#{cover},data=#{data},camera=#{camera} where uid = #{uid} and sid = #{sid}")
boolean updateScheme(SchemeInfo schemeInfo);
@Select("select name,data,camera,share,password from tb_scheme where uid = #{uid} and sid = #{sid}")
SchemeInfo getSchemeInfo(Map para);
@Update("update tb_scheme set share = #{share} ,password = #{password} where uid = #{uid} and sid = #{sid}")
boolean updateShareInfo(SchemeInfo schemeInfo);
@Select("select share from tb_scheme where sid = #{sid}")
Integer getShareBySid(String sid);
@Select("select name,data,camera from tb_scheme where sid = #{sid}")
SchemeInfo getSchemeInfoBySid(String sid);
@Select("select count(*) from tb_scheme where sid = #{sid} and password = #{password} and share = 2")
int getCustomer(Map para);
@Delete("delete from tb_scheme where sid = #{sid} and uid = #{uid}")
boolean deleteScheme(Map para);
}

@ -0,0 +1,24 @@
package com.tonkia.v3dmodel.mapper;
import com.tonkia.v3dmodel.pojo.UserInfo;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.Map;
public interface UserMapper {
@Select("select * from tb_user where phoneNumber = #{phoneNumber}")
UserInfo getUserInfo(UserInfo userInfo);
@Select("select userName, avatar from tb_user where uid = #{uid}")
UserInfo getHomeUserInfo(Integer uid);
@Update("update tb_user set avatar =#{avatar} where uid = #{uid} ")
boolean updateAvatar(Map para);
@Update("update tb_user set userName =#{userName} where uid = #{uid} ")
boolean updateUserName(Map para);
@Update("update tb_user set password =#{password} where uid = #{uid} ")
boolean updatePassword(Map para);
}

@ -0,0 +1,24 @@
package com.tonkia.v3dmodel.pojo;
import java.util.Date;
public class CommentInfo {
private String text;
private Date time;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
}

@ -0,0 +1,13 @@
package com.tonkia.v3dmodel.pojo;
public class CustomerInfo {
private String sid;
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
}

@ -0,0 +1,78 @@
package com.tonkia.v3dmodel.pojo;
import java.util.Date;
public class FileInfo {
private String fid;
private String sid;
private Integer uid;
private String name;
private String path;
private Date uploadTime;
private Integer state;
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getFid() {
return fid;
}
public void setFid(String fid) {
this.fid = fid;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public Date getUploadTime() {
return uploadTime;
}
public void setUploadTime(Date uploadTime) {
this.uploadTime = uploadTime;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
}

@ -0,0 +1,31 @@
package com.tonkia.v3dmodel.pojo;
public class FileRely {
private String fid;
private String name;
private String path;
public String getFid() {
return fid;
}
public void setFid(String fid) {
this.fid = fid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}

@ -0,0 +1,43 @@
package com.tonkia.v3dmodel.pojo;
public class ResponseData {
//code编码
public static int SUCCEED=0;
public static int FAILURE=1;
public static int FAILURE_UNLOGIN=2;
//返回格式
private int code;
private String msg;
private Object data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public ResponseData(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
}

@ -0,0 +1,105 @@
package com.tonkia.v3dmodel.pojo;
import java.util.Date;
public class SchemeInfo {
private String sid;
private Integer uid;
private String name;
private String cover;
private Integer state;
private Date createTime;
private Object data;
private Object camera;
private Integer share;
private String password;
private String shareLink;
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCover() {
return cover;
}
public void setCover(String cover) {
this.cover = cover;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Object getCamera() {
return camera;
}
public void setCamera(Object camera) {
this.camera = camera;
}
public Integer getShare() {
return share;
}
public void setShare(Integer share) {
this.share = share;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getShareLink() {
return shareLink;
}
public void setShareLink(String shareLink) {
this.shareLink = shareLink;
}
}

@ -0,0 +1,69 @@
package com.tonkia.v3dmodel.pojo;
import java.util.Date;
public class UserInfo {
private Integer uid;
private String phoneNumber;
private String userName;
private String password;
private Integer state;
private Date regTime;
private String avatar;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getState() {
return state;
}
public void setState(Integer state) {
this.state = state;
}
public Date getRegTime() {
return regTime;
}
public void setRegTime(Date regTime) {
this.regTime = regTime;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
}

@ -0,0 +1,11 @@
package com.tonkia.v3dmodel.service;
import com.tonkia.v3dmodel.pojo.CommentInfo;
import java.util.List;
public interface CommentService {
List<CommentInfo> getAllComment(String sid);
boolean insertComment(String sid, String text);
}

@ -0,0 +1,25 @@
package com.tonkia.v3dmodel.service;
import com.tonkia.v3dmodel.pojo.CustomerInfo;
import com.tonkia.v3dmodel.pojo.FileInfo;
import com.tonkia.v3dmodel.pojo.FileRely;
import com.tonkia.v3dmodel.pojo.UserInfo;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.List;
public interface FileService {
void download(UserInfo userInfo, CustomerInfo customerInfo, String type, String sid, String fileName, HttpServletResponse response, Integer size);
List<FileRely> insertModelFile(UserInfo userInfo, String sid, MultipartFile[] files);
List<FileRely> insertTextureFile(UserInfo userInfo, String sid, MultipartFile[] files);
String insertCoverFile(String sid,MultipartFile file);
String uploadAvatar(int uid ,MultipartFile file);
void avatar(Integer uid, String fileName, HttpServletResponse response);
}

@ -0,0 +1,29 @@
package com.tonkia.v3dmodel.service;
import com.tonkia.v3dmodel.pojo.SchemeInfo;
import com.tonkia.v3dmodel.pojo.UserInfo;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public interface SchemeService {
String insertScheme(SchemeInfo schemeInfo, UserInfo userInfo);
List<SchemeInfo> getHomeSchemeList(Integer uid);
boolean hasPermission(String sid, UserInfo userInfo);
boolean updateScheme(SchemeInfo schemeInfo);
SchemeInfo getSchemeInfo(Integer uid, String sid);
boolean updateShareInfo(SchemeInfo schemeInfo);
Integer getShareBySid(String sid);
SchemeInfo getSchemeInfo(String sid);
boolean getCustomer(String sid, String password);
boolean deleteScheme(Integer uid, String sid);
}

@ -0,0 +1,13 @@
package com.tonkia.v3dmodel.service;
import com.tonkia.v3dmodel.pojo.UserInfo;
public interface UserService {
UserInfo getUserInfo(UserInfo userInfo);
UserInfo getHomeUserInfo(Integer uid);
boolean updateAvatar(Integer uid, String path);
boolean updateInfo(Integer uid, String userName, String password);
}

@ -0,0 +1,31 @@
package com.tonkia.v3dmodel.service.impl;
import com.tonkia.v3dmodel.mapper.CommentMapper;
import com.tonkia.v3dmodel.pojo.CommentInfo;
import com.tonkia.v3dmodel.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.xml.stream.events.Comment;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class CommentServiceImpl implements CommentService {
@Autowired
CommentMapper commentMapper;
@Override
public List<CommentInfo> getAllComment(String sid) {
return commentMapper.getAllComment(sid);
}
@Override
public boolean insertComment(String sid, String text) {
Map para = new HashMap<>();
para.put("sid", sid);
para.put("text", text);
return commentMapper.insertComment(para);
}
}

@ -0,0 +1,196 @@
package com.tonkia.v3dmodel.service.impl;
import com.tonkia.v3dmodel.mapper.FileMapper;
import com.tonkia.v3dmodel.mapper.SchemeMapper;
import com.tonkia.v3dmodel.pojo.CustomerInfo;
import com.tonkia.v3dmodel.pojo.FileInfo;
import com.tonkia.v3dmodel.pojo.FileRely;
import com.tonkia.v3dmodel.pojo.UserInfo;
import com.tonkia.v3dmodel.service.FileService;
import com.tonkia.v3dmodel.utils.FtpUtil;
import com.tonkia.v3dmodel.utils.ThumbUtil;
import com.tonkia.v3dmodel.utils.UUIDUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class FileServiceImpl implements FileService {
@Autowired
FileMapper fileMapper;
@Autowired
SchemeMapper schemeMapper;
@Value("${ftpclient.host}")
private String host;
@Value("${ftpclient.port}")
private int port;
@Value("${ftpclient.username}")
private String username;
@Value("${ftpclient.password}")
private String password;
@Value("${ftpclient.basePath}")
private String basePath;
@Value("${ftpclient.filePath}")
private String filePath;
@Value("${ftpclient.downloadPathPrefix}")
private String downloadPathPrefix;
@Override
public List<FileRely> insertModelFile(UserInfo userInfo, String sid, MultipartFile[] files) {
int uid = userInfo.getUid();
List<FileRely> list = new ArrayList<>();
for (MultipartFile file : files) {
//判断是否是 .obj 或者 .fbx
String subfix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
if (subfix.toLowerCase().equals(".obj") || subfix.toLowerCase().equals(".fbx")) {
String fileName = UUIDUtil.generate() + subfix;
boolean isSucceed = false;
try {
isSucceed = FtpUtil.uploadFile(host, port, username, password, basePath, filePath + "/models/" + sid, fileName, file.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
if (isSucceed) {
FileRely fr = new FileRely();
FileInfo fi = new FileInfo();
String name = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf('.'));
String fid = UUIDUtil.generate();
String path = downloadPathPrefix + "/models/" + sid + "/" + fileName;
fi.setFid(fid);
fi.setUid(uid);
fi.setSid(sid);
fi.setName(name);
fi.setPath(path);
fi.setType(file.getContentType());
if (fileMapper.insertFile(fi)) {
fr.setFid(fid);
fr.setName(name);
fr.setPath(path);
list.add(fr);
}
}
}
}
return list;
}
@Override
public List<FileRely> insertTextureFile(UserInfo userInfo, String sid, MultipartFile[] files) {
int uid = userInfo.getUid();
List<FileRely> list = new ArrayList<>();
for (MultipartFile file : files) {
//判断是否是 .jpg 或者 .png
String subfix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
if (subfix.toLowerCase().equals(".jpg") || subfix.toLowerCase().equals(".png")) {
String fileName = UUIDUtil.generate() + subfix;
boolean isSucceed = false;
try {
isSucceed = FtpUtil.uploadFile(host, port, username, password, basePath, filePath + "/textures/" + sid, fileName, file.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
if (isSucceed) {
FileRely fr = new FileRely();
FileInfo fi = new FileInfo();
String name = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf('.'));
String fid = UUIDUtil.generate();
String path = downloadPathPrefix + "/textures/" + sid + "/" + fileName;
fi.setFid(fid);
fi.setUid(uid);
fi.setSid(sid);
fi.setName(name);
fi.setPath(path);
fi.setType(file.getContentType());
if (fileMapper.insertFile(fi)) {
fr.setFid(fid);
fr.setName(name);
fr.setPath(path);
list.add(fr);
}
}
}
}
return list;
}
@Override
public String insertCoverFile(String sid, MultipartFile file) {
String subfix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
String fileName = UUIDUtil.generate() + subfix;
boolean isSucceed = false;
try {
isSucceed = FtpUtil.uploadFile(host, port, username, password, basePath, filePath + "/cover/" + sid, fileName, file.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
if (isSucceed) {
String path = downloadPathPrefix + "/cover/" + sid + "/" + fileName;
return path;
}
return null;
}
@Override
public String uploadAvatar(int uid, MultipartFile file) {
String fileName = UUIDUtil.generate();
boolean isSucceed = false;
try {
isSucceed = FtpUtil.uploadFile(host, port, username, password, basePath, filePath + "/avatar/" + uid, fileName, file.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
if (isSucceed) {
String path = "/file/avatar/" + fileName;
return path;
}
return null;
}
@Override
public void avatar(Integer uid, String fileName, HttpServletResponse response) {
FtpUtil.downloadFileWithProgress(host, port, username, password, basePath + filePath + "/avatar/" + uid, fileName, response);
}
@Override
public void download(UserInfo userInfo, CustomerInfo customerInfo, String type, String sid, String fileName, HttpServletResponse response, Integer size) {
boolean hasRight = false;
int share = schemeMapper.getShareBySid(sid);
if (share == 1) {
hasRight = true;
} else if (userInfo != null) {
Map para = new HashMap<>();
para.put("uid", userInfo.getUid());
para.put("sid", sid);
hasRight = schemeMapper.hasPermission(para) > 0;
} else if (share == 2 && customerInfo != null && customerInfo.getSid().equals(sid)) {
hasRight = customerInfo.getSid().equals(sid);
}
if (hasRight) {
try {
if (size == null)
FtpUtil.downloadFileWithProgress(host, port, username, password, basePath + filePath + "/" + type + "/" + sid, fileName, response);
else {
//如果指定了size返回压缩缩略图
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FtpUtil.downloadFile(host, port, username, password, basePath + filePath + "/" + type + "/" + sid, fileName, baos);
ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());
ThumbUtil.thumb(swapStream, response.getOutputStream(), size);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

@ -0,0 +1,101 @@
package com.tonkia.v3dmodel.service.impl;
import com.tonkia.v3dmodel.mapper.SchemeMapper;
import com.tonkia.v3dmodel.pojo.SchemeInfo;
import com.tonkia.v3dmodel.pojo.UserInfo;
import com.tonkia.v3dmodel.service.SchemeService;
import com.tonkia.v3dmodel.utils.UUIDUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class SchemeServiceImpl implements SchemeService {
@Autowired
SchemeMapper schemeMapper;
@Value("${shareLink.prefix}")
String shareLinkPrefix;
@Override
public String insertScheme(SchemeInfo schemeInfo, UserInfo userInfo) {
String sid = UUIDUtil.generate();
schemeInfo.setSid(sid);
schemeInfo.setCreateTime(new Date());
schemeInfo.setUid(userInfo.getUid());
return schemeMapper.insertScheme(schemeInfo) ? sid : null;
}
@Override
public List<SchemeInfo> getHomeSchemeList(Integer uid) {
List<SchemeInfo> list = schemeMapper.getHomeSchemeList(uid);
for (SchemeInfo schemeInfo : list) {
schemeInfo.setShareLink(shareLinkPrefix + schemeInfo.getSid());
}
return list;
}
@Override
public boolean hasPermission(String sid, UserInfo userInfo) {
Map para = new HashMap<>();
para.put("uid", userInfo.getUid());
para.put("sid", sid);
return schemeMapper.hasPermission(para) > 0;
}
@Override
public boolean updateScheme(SchemeInfo schemeInfo) {
return schemeMapper.updateScheme(schemeInfo);
}
@Override
public SchemeInfo getSchemeInfo(Integer uid, String sid) {
Map para = new HashMap<>();
para.put("uid", uid);
para.put("sid", sid);
SchemeInfo schemeInfo = schemeMapper.getSchemeInfo(para);
if (schemeInfo != null)
schemeInfo.setShareLink(shareLinkPrefix + sid);
return schemeInfo;
}
@Override
public boolean updateShareInfo(SchemeInfo schemeInfo) {
return schemeMapper.updateShareInfo(schemeInfo);
}
@Override
public Integer getShareBySid(String sid) {
return schemeMapper.getShareBySid(sid);
}
@Override
public SchemeInfo getSchemeInfo(String sid) {
return schemeMapper.getSchemeInfoBySid(sid);
}
@Override
public boolean getCustomer(String sid, String password) {
Map para = new HashMap<>();
para.put("password", password);
para.put("sid", sid);
return schemeMapper.getCustomer(para)>0;
}
@Override
public boolean deleteScheme(Integer uid, String sid) {
Map para = new HashMap<>();
para.put("uid", uid);
para.put("sid", sid);
return schemeMapper.deleteScheme(para);
}
}

@ -0,0 +1,61 @@
package com.tonkia.v3dmodel.service.impl;
import com.tonkia.v3dmodel.mapper.UserMapper;
import com.tonkia.v3dmodel.pojo.UserInfo;
import com.tonkia.v3dmodel.service.UserService;
import org.apache.http.util.TextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public UserInfo getUserInfo(UserInfo userInfo) {
return userMapper.getUserInfo(userInfo);
}
/**
* 获取主页的用户信息关键信息需要保留
*
* @param uid
* @return
*/
@Override
public UserInfo getHomeUserInfo(Integer uid) {
return userMapper.getHomeUserInfo(uid);
}
@Override
public boolean updateAvatar(Integer uid, String path) {
Map para = new HashMap();
para.put("uid", uid);
para.put("avatar", path);
return userMapper.updateAvatar(para);
}
@Override
public boolean updateInfo(Integer uid, String userName, String password) {
boolean res = false;
if (!TextUtils.isEmpty(userName)) {
Map para = new HashMap();
para.put("uid", uid);
para.put("userName", userName);
res = res || userMapper.updateUserName(para);
}
if (!TextUtils.isEmpty(password)) {
Map para = new HashMap();
para.put("uid", uid);
para.put("password", password);
res = res || userMapper.updatePassword(para);
}
return res;
}
}

@ -0,0 +1,173 @@
package com.tonkia.v3dmodel.utils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class FtpUtil {
/**
*  
* Description: 向FTP服务器上传文件 
*
* @param host FTP服务器hostname 
* @param port FTP服务器端口 
* @param username FTP登录账号 
* @param password FTP登录密码 
* @param basePath FTP服务器基础目录
* @param filePath FTP服务器文件存放路径例如分日期存放/2015/01/01文件的路径为basePath+filePath
* @param filename 上传到FTP服务器上的文件名 
* @param input 输入流 
* @return 成功返回true否则返回false 
*/
public static boolean uploadFile(String host, int port, String username, String password, String basePath,
String filePath, String filename, InputStream input) {
boolean result = false;
FTPClient ftp = new FTPClient();
try {
int reply;
ftp.connect(host, port);
ftp.login(username, password);
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return result;
}
//切换到上传目录
if (!ftp.changeWorkingDirectory(basePath + filePath)) {
//如果目录不存在创建目录
String[] dirs = filePath.split("/");
String tempPath = basePath;
for (String dir : dirs) {
if (null == dir || "".equals(dir)) continue;
tempPath += "/" + dir;
if (!ftp.changeWorkingDirectory(tempPath)) {
if (!ftp.makeDirectory(tempPath)) {
return result;
} else {
ftp.changeWorkingDirectory(tempPath);
}
}
}
}
//设置上传文件的类型为二进制类型
ftp.setFileType(FTP.BINARY_FILE_TYPE);
//上传文件
if (!ftp.storeFile(filename, input)) {
return result;
}
input.close();
ftp.logout();
result = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
return result;
}
/**
*  
* Description: 从FTP服务器下载文件 
*
* @param host FTP服务器hostname 
* @param port FTP服务器端口 
* @param username FTP登录账号 
* @param password FTP登录密码 
* @param remotePath FTP服务器上的相对路径 
* @param fileName 要下载的文件名 
* @param output 输出流 
* @return 
*/
public static boolean downloadFile(String host, int port, String username, String password, String remotePath,
String fileName, OutputStream output) {
boolean result = false;
FTPClient ftp = new FTPClient();
try {
int reply;
ftp.connect(host, port);
ftp.login(username, password);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return result;
}
ftp.changeWorkingDirectory(remotePath);
FTPFile[] fs = ftp.listFiles();
for (FTPFile ff : fs) {
if (ff.getName().equals(fileName)) {
ftp.retrieveFile(ff.getName(), output);
}
}
output.close();
ftp.logout();
result = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return result;
}
public static boolean downloadFileWithProgress(String host, int port, String username, String password, String remotePath, String fileName, HttpServletResponse response) {
boolean result = false;
FTPClient ftp = new FTPClient();
try {
int reply;
ftp.connect(host, port);
ftp.login(username, password);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return result;
}
ftp.changeWorkingDirectory(remotePath);
FTPFile[] fs = ftp.listFiles();
for (FTPFile ff : fs) {
if (ff.getName().equals(fileName)) {
response.setHeader("Content-Length", ff.getSize() + "");
ftp.retrieveFile(ff.getName(), response.getOutputStream());
}
}
response.getOutputStream().close();
ftp.logout();
result = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return result;
}
}

@ -0,0 +1,13 @@
package com.tonkia.v3dmodel.utils;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Test {
public static void main(String[] args) throws IOException {
InputStream is = new FileInputStream("d:/web.png");
boolean res = FtpUtil.uploadFile("192.168.226.128", 21, "ftpuser", "123456", "/home/ftpuser", "/v3d", "target", is);
System.out.println(res);
}
}

@ -0,0 +1,17 @@
package com.tonkia.v3dmodel.utils;
import net.coobird.thumbnailator.Thumbnails;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class ThumbUtil {
public static void thumb(InputStream is, OutputStream os, int size) {
try {
Thumbnails.of(is).size(size, size).outputQuality(0.5).toOutputStream(os);
} catch (IOException e) {
e.printStackTrace();
}
}
}

@ -0,0 +1,13 @@
package com.tonkia.v3dmodel.utils;
import java.util.UUID;
public class UUIDUtil {
public static String generate() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
public static void main(String[] args) {
System.out.println(generate());
}
}

@ -0,0 +1,12 @@
#ftpclient.host=134.175.111.158
ftpclient.host=192.168.226.129
ftpclient.port=21
ftpclient.username=ftpuser
#ftpclient.password=41509060104
ftpclient.password=123456
ftpclient.basePath=/home/ftpuser
ftpclient.filePath=/v3d
ftpclient.downloadPathPrefix=/file/download
shareLink.prefix=http://192.168.43.208/#/show/
#shareLink.prefix=http://v3d.tonkia.xyz/#/show/

@ -0,0 +1,4 @@
jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/v3dmodel?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
jdbc.username=root
jdbc.password=123456

@ -0,0 +1,5 @@
log4j.rootLogger=DEBUG,Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--引入配置文件,多个用逗号隔开-->
<context:property-placeholder location="classpath:db.properties,classpath:cfg.properties"/>
<!-- 启用springmvc注解-->
<mvc:annotation-driven/>
<!-- 设置使用注解的类路径 -->
<context:component-scan base-package="com.tonkia.v3dmodel.controller,com.tonkia.v3dmodel.service.impl"/>
<!--<context:annotation-config/>-->
<!-- 静态文件处理 -->
<mvc:resources location="/css/" mapping="/css/**/"/>
<mvc:resources location="/js/" mapping="/js/**/"/>
<mvc:resources location="/img/" mapping="/img/**/"/>
<mvc:resources location="/ueditor/" mapping="/ueditor/**/"/>
<!-- 文件上传-->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"/>
<property name="maxUploadSize" value="10240000"/>
<property name="maxInMemorySize" value="10240000"/>
<property name="resolveLazily" value="true"/>
</bean>
<!-- druid数据源 -->
<bean id="ds" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="initialSize" value="2"/>
<property name="minIdle" value="1"/>
<property name="maxActive" value="20"/>
<property name="maxWait" value="60000"/>
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<property name="minEvictableIdleTimeMillis" value="300000"/>
<property name="validationQuery" value="SELECT 'x' from dual "/>
<property name="testWhileIdle" value="true"/>
<property name="testOnBorrow" value="false"/>
<property name="testOnReturn" value="false"/>
<property name="poolPreparedStatements" value="true"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="20"/>
</bean>
<!-- 配置mybatis -->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
<property name="basePackage" value="com.tonkia.v3dmodel.mapper"/>
</bean>
<!-- 事务管理器 -->
<bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="tm">
<tx:attributes>
<tx:method name="insert*"/>
<tx:method name="delete*"/>
<tx:method name="update*"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.tonkia.v3dmodel.service.impl.*.*(..))"/>
</aop:config>
<!--shiro-->
<!--<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">-->
<!--<property name="securityManager" ref="securityManager"/>-->
<!--<property name="loginUrl" value="/login"/>-->
<!--<property name="unauthorizedUrl" value="/refuse"/>-->
<!--<property name="filterChainDefinitions">-->
<!--<value>-->
<!--/test/**=anon-->
<!--/=user-->
<!--/logout=logout-->
<!--/**=authc-->
<!--</value>-->
<!--</property>-->
<!--</bean>-->
<!--&lt;!&ndash;securityManager&ndash;&gt;-->
<!--<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">-->
<!--<property name="realm" ref="userRealm"/>-->
<!--<property name="sessionManager" ref="sessionManager"/>-->
<!--&lt;!&ndash;<property name="cacheManager" ref="cacheManager"/>&ndash;&gt;-->
<!--</bean>-->
<!--<bean id="userRealm" class="com.tonkia.v3dmodel.realm.UserRealm"/>-->
<!--&lt;!&ndash;sessionManager&ndash;&gt;-->
<!--<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">-->
<!--<property name="sessionIdUrlRewritingEnabled" value="false"/>-->
<!--<property name="deleteInvalidSessions" value="true"/>-->
<!--<property name="globalSessionTimeout" value="600000"/>-->
<!--</bean>-->
<!--&lt;!&ndash; Ehcache缓存&ndash;&gt;-->
<!--&lt;!&ndash;<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"/>&ndash;&gt;-->
<!--&lt;!&ndash;启用注解&ndash;&gt;-->
<!--<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>-->
<!--<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"-->
<!--depends-on="lifecycleBeanPostProcessor">-->
<!--<property name="proxyTargetClass" value="true"/>-->
<!--</bean>-->
<!--<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">-->
<!--<property name="securityManager" ref="securityManager"/>-->
<!--</bean>-->
</beans>

@ -0,0 +1,55 @@
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--字符编码过滤器-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<!--shiro-->
<!--<filter>-->
<!--<filter-name>shiroFilter</filter-name>-->
<!--<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>-->
<!--<init-param>-->
<!--<param-name>targetFilterLifecycle</param-name>-->
<!--<param-value>true</param-value>-->
<!--</init-param>-->
<!--</filter>-->
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--<filter-mapping>-->
<!--<filter-name>shiroFilter</filter-name>-->
<!--<url-pattern>/*</url-pattern>-->
<!--</filter-mapping>-->
<!--springmvc-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.ico</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

@ -0,0 +1 @@
.v-enter{opacity:0;-webkit-transform:translateX(300px);transform:translateX(300px)}.v-leave-to{opacity:0;-webkit-transform:translateX(-300px);transform:translateX(-300px)}.v-enter-active,.v-leave-active{-webkit-transition:all .3s ease;transition:all .3s ease}.v-speed-dial{position:absolute}.v-btn--floating{position:relative}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

@ -0,0 +1,27 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<meta http-equiv=X-UA-Compatible content="IE=edge">
<meta name=viewport content="width=device-width,initial-scale=1">
<link rel=icon href=/favicon.ico>
<title>V3D</title>
<link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel=stylesheet href="https://fonts.googleapis.com/css?family=Material+Icons">
<script src=./js/inflate.min.js></script>
<link href=/css/app.a0a149c8.css rel=preload as=style>
<link href=/css/chunk-vendors.504cc259.css rel=preload as=style>
<link href=/js/app.f155bb4f.js rel=preload as=script>
<link href=/js/chunk-vendors.af4edcc5.js rel=preload as=script>
<link href=/css/chunk-vendors.504cc259.css rel=stylesheet>
<link href=/css/app.a0a149c8.css rel=stylesheet>
</head>
<body>
<noscript><strong>We're sorry but v3dmodel doesn't work properly without JavaScript enabled. Please enable it to
continue.</strong></noscript>
<div id=app></div>
<script src=/js/chunk-vendors.af4edcc5.js></script>
<script src=/js/app.f155bb4f.js></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,15 @@
/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */(function() {'use strict';var l=void 0,aa=this;function r(c,d){var a=c.split("."),b=aa;!(a[0]in b)&&b.execScript&&b.execScript("var "+a[0]);for(var e;a.length&&(e=a.shift());)!a.length&&d!==l?b[e]=d:b=b[e]?b[e]:b[e]={}};var t="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;function v(c){var d=c.length,a=0,b=Number.POSITIVE_INFINITY,e,f,g,h,k,m,n,p,s,x;for(p=0;p<d;++p)c[p]>a&&(a=c[p]),c[p]<b&&(b=c[p]);e=1<<a;f=new (t?Uint32Array:Array)(e);g=1;h=0;for(k=2;g<=a;){for(p=0;p<d;++p)if(c[p]===g){m=0;n=h;for(s=0;s<g;++s)m=m<<1|n&1,n>>=1;x=g<<16|p;for(s=m;s<e;s+=k)f[s]=x;++h}++g;h<<=1;k<<=1}return[f,a,b]};function w(c,d){this.g=[];this.h=32768;this.d=this.f=this.a=this.l=0;this.input=t?new Uint8Array(c):c;this.m=!1;this.i=y;this.r=!1;if(d||!(d={}))d.index&&(this.a=d.index),d.bufferSize&&(this.h=d.bufferSize),d.bufferType&&(this.i=d.bufferType),d.resize&&(this.r=d.resize);switch(this.i){case A:this.b=32768;this.c=new (t?Uint8Array:Array)(32768+this.h+258);break;case y:this.b=0;this.c=new (t?Uint8Array:Array)(this.h);this.e=this.z;this.n=this.v;this.j=this.w;break;default:throw Error("invalid inflate mode");
}}var A=0,y=1,B={t:A,s:y};
w.prototype.k=function(){for(;!this.m;){var c=C(this,3);c&1&&(this.m=!0);c>>>=1;switch(c){case 0:var d=this.input,a=this.a,b=this.c,e=this.b,f=d.length,g=l,h=l,k=b.length,m=l;this.d=this.f=0;if(a+1>=f)throw Error("invalid uncompressed block header: LEN");g=d[a++]|d[a++]<<8;if(a+1>=f)throw Error("invalid uncompressed block header: NLEN");h=d[a++]|d[a++]<<8;if(g===~h)throw Error("invalid uncompressed block header: length verify");if(a+g>d.length)throw Error("input buffer is broken");switch(this.i){case A:for(;e+
g>b.length;){m=k-e;g-=m;if(t)b.set(d.subarray(a,a+m),e),e+=m,a+=m;else for(;m--;)b[e++]=d[a++];this.b=e;b=this.e();e=this.b}break;case y:for(;e+g>b.length;)b=this.e({p:2});break;default:throw Error("invalid inflate mode");}if(t)b.set(d.subarray(a,a+g),e),e+=g,a+=g;else for(;g--;)b[e++]=d[a++];this.a=a;this.b=e;this.c=b;break;case 1:this.j(ba,ca);break;case 2:for(var n=C(this,5)+257,p=C(this,5)+1,s=C(this,4)+4,x=new (t?Uint8Array:Array)(D.length),S=l,T=l,U=l,u=l,M=l,F=l,z=l,q=l,V=l,q=0;q<s;++q)x[D[q]]=
C(this,3);if(!t){q=s;for(s=x.length;q<s;++q)x[D[q]]=0}S=v(x);u=new (t?Uint8Array:Array)(n+p);q=0;for(V=n+p;q<V;)switch(M=E(this,S),M){case 16:for(z=3+C(this,2);z--;)u[q++]=F;break;case 17:for(z=3+C(this,3);z--;)u[q++]=0;F=0;break;case 18:for(z=11+C(this,7);z--;)u[q++]=0;F=0;break;default:F=u[q++]=M}T=t?v(u.subarray(0,n)):v(u.slice(0,n));U=t?v(u.subarray(n)):v(u.slice(n));this.j(T,U);break;default:throw Error("unknown BTYPE: "+c);}}return this.n()};
var G=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],D=t?new Uint16Array(G):G,H=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],I=t?new Uint16Array(H):H,J=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],K=t?new Uint8Array(J):J,L=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],da=t?new Uint16Array(L):L,ea=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,
13,13],N=t?new Uint8Array(ea):ea,O=new (t?Uint8Array:Array)(288),P,fa;P=0;for(fa=O.length;P<fa;++P)O[P]=143>=P?8:255>=P?9:279>=P?7:8;var ba=v(O),Q=new (t?Uint8Array:Array)(30),R,ga;R=0;for(ga=Q.length;R<ga;++R)Q[R]=5;var ca=v(Q);function C(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h;b<d;){if(f>=g)throw Error("input buffer is broken");a|=e[f++]<<b;b+=8}h=a&(1<<d)-1;c.f=a>>>d;c.d=b-d;c.a=f;return h}
function E(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h=d[0],k=d[1],m,n;b<k&&!(f>=g);)a|=e[f++]<<b,b+=8;m=h[a&(1<<k)-1];n=m>>>16;if(n>b)throw Error("invalid code length: "+n);c.f=a>>n;c.d=b-n;c.a=f;return m&65535}
w.prototype.j=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length-258,f,g,h,k;256!==(f=E(this,c));)if(256>f)b>=e&&(this.b=b,a=this.e(),b=this.b),a[b++]=f;else{g=f-257;k=I[g];0<K[g]&&(k+=C(this,K[g]));f=E(this,d);h=da[f];0<N[f]&&(h+=C(this,N[f]));b>=e&&(this.b=b,a=this.e(),b=this.b);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
w.prototype.w=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length,f,g,h,k;256!==(f=E(this,c));)if(256>f)b>=e&&(a=this.e(),e=a.length),a[b++]=f;else{g=f-257;k=I[g];0<K[g]&&(k+=C(this,K[g]));f=E(this,d);h=da[f];0<N[f]&&(h+=C(this,N[f]));b+k>e&&(a=this.e(),e=a.length);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
w.prototype.e=function(){var c=new (t?Uint8Array:Array)(this.b-32768),d=this.b-32768,a,b,e=this.c;if(t)c.set(e.subarray(32768,c.length));else{a=0;for(b=c.length;a<b;++a)c[a]=e[a+32768]}this.g.push(c);this.l+=c.length;if(t)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];this.b=32768;return e};
w.prototype.z=function(c){var d,a=this.input.length/this.a+1|0,b,e,f,g=this.input,h=this.c;c&&("number"===typeof c.p&&(a=c.p),"number"===typeof c.u&&(a+=c.u));2>a?(b=(g.length-this.a)/this.o[2],f=258*(b/2)|0,e=f<h.length?h.length+f:h.length<<1):e=h.length*a;t?(d=new Uint8Array(e),d.set(h)):d=h;return this.c=d};
w.prototype.n=function(){var c=0,d=this.c,a=this.g,b,e=new (t?Uint8Array:Array)(this.l+(this.b-32768)),f,g,h,k;if(0===a.length)return t?this.c.subarray(32768,this.b):this.c.slice(32768,this.b);f=0;for(g=a.length;f<g;++f){b=a[f];h=0;for(k=b.length;h<k;++h)e[c++]=b[h]}f=32768;for(g=this.b;f<g;++f)e[c++]=d[f];this.g=[];return this.buffer=e};
w.prototype.v=function(){var c,d=this.b;t?this.r?(c=new Uint8Array(d),c.set(this.c.subarray(0,d))):c=this.c.subarray(0,d):(this.c.length>d&&(this.c.length=d),c=this.c);return this.buffer=c};function W(c,d){var a,b;this.input=c;this.a=0;if(d||!(d={}))d.index&&(this.a=d.index),d.verify&&(this.A=d.verify);a=c[this.a++];b=c[this.a++];switch(a&15){case ha:this.method=ha;break;default:throw Error("unsupported compression method");}if(0!==((a<<8)+b)%31)throw Error("invalid fcheck flag:"+((a<<8)+b)%31);if(b&32)throw Error("fdict flag is not supported");this.q=new w(c,{index:this.a,bufferSize:d.bufferSize,bufferType:d.bufferType,resize:d.resize})}
W.prototype.k=function(){var c=this.input,d,a;d=this.q.k();this.a=this.q.a;if(this.A){a=(c[this.a++]<<24|c[this.a++]<<16|c[this.a++]<<8|c[this.a++])>>>0;var b=d;if("string"===typeof b){var e=b.split(""),f,g;f=0;for(g=e.length;f<g;f++)e[f]=(e[f].charCodeAt(0)&255)>>>0;b=e}for(var h=1,k=0,m=b.length,n,p=0;0<m;){n=1024<m?1024:m;m-=n;do h+=b[p++],k+=h;while(--n);h%=65521;k%=65521}if(a!==(k<<16|h)>>>0)throw Error("invalid adler-32 checksum");}return d};var ha=8;r("Zlib.Inflate",W);r("Zlib.Inflate.prototype.decompress",W.prototype.k);var X={ADAPTIVE:B.s,BLOCK:B.t},Y,Z,$,ia;if(Object.keys)Y=Object.keys(X);else for(Z in Y=[],$=0,X)Y[$++]=Z;$=0;for(ia=Y.length;$<ia;++$)Z=Y[$],r("Zlib.Inflate.BufferType."+Z,X[Z]);}).call(this);

@ -0,0 +1,12 @@
#ftpclient.host=134.175.111.158
ftpclient.host=192.168.226.129
ftpclient.port=21
ftpclient.username=ftpuser
#ftpclient.password=41509060104
ftpclient.password=123456
ftpclient.basePath=/home/ftpuser
ftpclient.filePath=/v3d
ftpclient.downloadPathPrefix=/file/download
shareLink.prefix=http://192.168.43.208/#/show/
#shareLink.prefix=http://v3d.tonkia.xyz/#/show/

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save