Browse Source

第一版

黎海 1 year ago
parent
commit
ad2db0e7ec

+ 1 - 1
babel.config.js

@@ -4,7 +4,7 @@ module.exports = {
4 4
   presets: [
5 5
     ['taro', {
6 6
       framework: 'react',
7
-      ts: false
7
+      ts: true
8 8
     }]
9 9
   ]
10 10
 }

File diff suppressed because it is too large
+ 19652 - 19652
package-lock.json


+ 2 - 2
package.json

@@ -53,7 +53,7 @@
53 53
         "@tarojs/runtime": "3.5.7",
54 54
         "@tarojs/shared": "3.5.7",
55 55
         "@tarojs/taro": "3.5.7",
56
-        "@tarojs/taro-h5": "3.5.7",
56
+        "@tarojs/taro-h5": "^3.5.7",
57 57
         "@vant/weapp": "^1.10.14",
58 58
         "postcss": "^8.2.1",
59 59
         "react": "^18.0.0",
@@ -81,4 +81,4 @@
81 81
         "version": "1.3.3",
82 82
         "desc": "添加广告"
83 83
     }
84
-}
84
+}

+ 2 - 2
src/api/config.js

@@ -1,7 +1,7 @@
1 1
 // 配置请求对象
2 2
 // 本地调试 dev 开发阶段
3
-export const baseUrl = "https://test-openai.fyshark.com";//测试
4
-// export const baseUrl = "https://api-video.fyshz.com";//正式
3
+// export const baseUrl = "https://test-openai.fyshark.com";//测试
4
+export const baseUrl = "https://openai.fyshark.com";//正式
5 5
 // product 阶段
6 6
 // https://www.fastmock.site/mock/3f112f6cb2f621fc9c2dd6a14be19f38/beers/
7 7
 // 设计模式

+ 9 - 3
src/app.config.js

@@ -1,15 +1,21 @@
1
+
2
+import Taro from '@tarojs/taro'
1 3
 export default defineAppConfig({
2 4
   pages: [
3 5
     'pages/index/index',
4 6
     'pages/collection/index',
5 7
     "pages/darwDetail/index",
6
-    "pages/mine/index"
8
+    "pages/communityDetail/index",
9
+    "pages/earnPoints/index",
10
+    "pages/mine/index",
11
+
7 12
   ],
8 13
   window: {
9 14
     backgroundTextStyle: 'light',
10 15
     navigationBarBackgroundColor: '#041129',
11 16
     navigationBarTitleText: 'AI绘画',
12
-    navigationBarTextStyle: 'white'
17
+    navigationBarTextStyle: 'white',
18
+    backgroundColor: "#041129"
13 19
   },
14 20
   tabBar: {
15 21
     color: "#C6C6C6",
@@ -21,7 +27,7 @@ export default defineAppConfig({
21 27
         pagePath: "pages/collection/index",
22 28
         iconPath: "images/nav/like.png",
23 29
         selectedIconPath: "images/nav/like_pin.png",
24
-        text: "拓展"
30
+        text: "社区"
25 31
 
26 32
       },
27 33
       {

+ 12 - 10
src/app.js

@@ -24,22 +24,24 @@ class App extends Component {
24 24
     })
25 25
     // 获取路由参数
26 26
     let params = this.$instance.router.params
27
-    console.log(params, 'params');
27
+    if (params.scene) {
28
+      let _scene = decodeURIComponent(params.scene)
29
+      const arr = _scene.split("=");
30
+      const result1 = arr[1].split("&")[0]; // 去掉第二个等号后面的"&"符号
31
+      const result2 = arr[2]; // 第三个等号后面的内容
32
+      Taro.setStorageSync('channel_name',result1)
33
+      Taro.setStorageSync('source_name', result2)
34
+    }
28 35
     let item = params
29
-    if (params.channel_name) {
30
-      Taro.setStorageSync('channel_name', item.channel_name)
36
+    if (params.c) {
37
+      Taro.setStorageSync('channel_name', item.c)
31 38
     }
32
-    if (params.source_name) {
33
-      Taro.setStorageSync('source_name', item.source_name)
39
+    if (params.s) {
40
+      Taro.setStorageSync('source_name', item.s)
34 41
     }
35
-
36 42
     Taro.setKeepScreenOn({
37 43
       keepScreenOn: true
38 44
     })
39
-
40
-
41
-
42
-
43 45
   }
44 46
 
45 47
   componentDidHide () { }

+ 37 - 8
src/common/tool.js

@@ -1,6 +1,8 @@
1 1
 import Taro from '@tarojs/taro'
2 2
 import * as api from '../service/index'
3 3
 const tool = {
4
+  shareTitle:'一款属于自己的AI绘画小程序,快来创作属于自己的独家作品吧。',
5
+  shareImg:'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679623995925.png',
4 6
   //去登录
5 7
   toLogin: function (rescallback = () => { }) {
6 8
     Taro.login({
@@ -14,6 +16,10 @@ const tool = {
14 16
               key: "session_key",
15 17
               data: item.data.session_key
16 18
             })
19
+            Taro.setStorage({
20
+              key: "user_id",
21
+              data: item.data.id
22
+            })
17 23
           })
18 24
         } else {
19 25
         }
@@ -27,7 +33,30 @@ const tool = {
27 33
     // 如果随机数不足四位,则在前面补零
28 34
     return randomNumber.toString().padStart(4, '0');
29 35
   },
30
-
36
+  //判断不为安卓
37
+  notAndroid: function () {
38
+    let is_ios = false;
39
+    Taro.getSystemInfo({
40
+      success: function (res) {
41
+        if (res.platform != "android") {
42
+          is_ios = true
43
+        }
44
+      }
45
+    })
46
+    return is_ios;
47
+  },
48
+  //判断是否为安卓
49
+  isAndroid: function () {
50
+    let is_android = false;
51
+    Taro.getSystemInfo({
52
+      success: function (res) {
53
+        if (res.platform == "android") {
54
+          is_android = true
55
+        }
56
+      }
57
+    })
58
+    return is_android;
59
+  },
31 60
   // 生成用户ID的函数
32 61
   generateUserID () {
33 62
     // 获取当前时间戳
@@ -36,15 +65,15 @@ const tool = {
36 65
     const randomNumber = this.generateRandomNumber();
37 66
     // 将时间戳和随机数拼接起来,得到用户ID
38 67
     const userID = timestamp + randomNumber;
39
-    console.log(userID,'userID');
68
+    console.log(userID, 'userID');
40 69
     return userID;
41 70
   },
42
-   /**
43
- * 限制字符串长度
44
- * value:字符串对象
45
- * lmit:展示的长度
46
- */
47
-   ellipsis: function (value, lmit) {
71
+  /**
72
+* 限制字符串长度
73
+* value:字符串对象
74
+* lmit:展示的长度
75
+*/
76
+  ellipsis: function (value, lmit) {
48 77
     if (!value) return ''
49 78
     if (value.length > lmit) {
50 79
       return value.slice(0, lmit) + '...'

+ 16 - 0
src/component/taro-plugin-canvas/index.css

@@ -0,0 +1,16 @@
1
+.canvas {
2
+  width: 750rpx;
3
+  height: 750rpx;
4
+}
5
+.canvas.pro {
6
+  position: absolute;
7
+  bottom: 0;
8
+  left: 0;
9
+  transform: translate3d(-9999rpx, 0, 0);
10
+}
11
+.canvas.debug {
12
+  position: absolute;
13
+  bottom: 0;
14
+  left: 0;
15
+  border: 1rpx solid #ccc;
16
+}

+ 322 - 0
src/component/taro-plugin-canvas/index.tsx

@@ -0,0 +1,322 @@
1
+import Taro, { CanvasContext } from '@tarojs/taro';
2
+import { Component } from 'react'
3
+import PropTypes from 'prop-types';
4
+import { Canvas } from '@tarojs/components';
5
+import { randomString, getHeight, downloadImageAndInfo } from './utils/tools';
6
+import {
7
+  drawImage,
8
+  drawText,
9
+  drawBlock,
10
+  drawLine,
11
+} from './utils/draw';
12
+import { IConfig, IIMage } from './types';
13
+import './index.css';
14
+
15
+interface ICanvasDrawerProps {
16
+  config: IConfig;
17
+  onCreateSuccess: (res: any) => void;
18
+  onCreateFail: (err: Error) => void;
19
+}
20
+
21
+interface ICanvasDrawerState {
22
+  pxWidth: number;
23
+  pxHeight: number;
24
+  debug: boolean;
25
+  factor: number;
26
+  pixelRatio: number;
27
+}
28
+
29
+
30
+let count = 1;
31
+export default class CanvasDrawer extends Component<ICanvasDrawerProps, ICanvasDrawerState> {
32
+  cache: any;
33
+  drawArr: any[];
34
+  canvasId: string;
35
+  ctx: CanvasContext | null;
36
+
37
+  static propTypes = {
38
+    config: PropTypes.object.isRequired,
39
+    onCreateSuccess: PropTypes.func.isRequired,
40
+    onCreateFail: PropTypes.func.isRequired,
41
+  };
42
+
43
+  static defaultProps = {};
44
+
45
+  constructor(props) {
46
+    super(props);
47
+    this.state = {
48
+      pxWidth: 0,
49
+      pxHeight: 0,
50
+      debug: false,
51
+      factor: 0,
52
+      pixelRatio: 1,
53
+    }
54
+    this.canvasId = randomString(10);
55
+    this.ctx = null;
56
+    this.cache = {};
57
+    this.drawArr = [];
58
+  }
59
+
60
+  componentWillMount() {
61
+    const { config } = this.props;
62
+    const height = getHeight(config);
63
+    this.initCanvas(config.width, height, config.debug);
64
+  }
65
+
66
+  componentDidMount() {
67
+    const sysInfo = Taro.getSystemInfoSync();
68
+    const screenWidth = sysInfo.screenWidth;
69
+    this.setState({
70
+      factor: screenWidth / 750
71
+    })
72
+    this.onCreate();
73
+  }
74
+
75
+  componentWillUnmount() { }
76
+
77
+  /**
78
+   * @description rpx => px 基础方法
79
+   * @param { number } rpx - 需要转换的数值
80
+   * @param { boolean} int - 是否为 int
81
+   * @param { number } [factor = this.state.factor] - 转化因子
82
+   * @returns { number }
83
+   */
84
+  toPx = (rpx: number, int: boolean = false, factor: number = this.state.factor) => {
85
+    if (int) {
86
+      return Math.ceil(rpx * factor * this.state.pixelRatio);
87
+    }
88
+    return rpx * factor * this.state.pixelRatio;
89
+  }
90
+  /**
91
+   * @description px => rpx
92
+   * @param { number } px - 需要转换的数值
93
+   * @param { boolean} int - 是否为 int
94
+   * @param { number } [factor = this.state.factor] - 转化因子
95
+   * @returns { number }
96
+   */
97
+  toRpx = (px: number, int: boolean = false, factor: number = this.state.factor) => {
98
+    if (int) {
99
+      return Math.ceil(px / factor);
100
+    }
101
+    return px / factor;
102
+  }
103
+
104
+  /**
105
+   * @description 下载图片并获取图片信息
106
+   * @param  {} image
107
+   * @param  {} index
108
+   */
109
+  _downloadImageAndInfo = (image: IIMage, index: number, pixelRatio: number) => {
110
+    return new Promise<any>((resolve, reject) => {
111
+      downloadImageAndInfo(image, index, this.toRpx, pixelRatio)
112
+        .then(
113
+          (result) => {
114
+            this.drawArr.push(result);
115
+            resolve(result);
116
+          }
117
+        )
118
+        .catch(err => {
119
+          console.log(err);
120
+          reject(err)
121
+        });
122
+    })
123
+  }
124
+  /**
125
+   * @param  {} images=[]
126
+   */
127
+  downloadResource = ({ images = [], pixelRatio = 1 }: { images: IIMage[], pixelRatio: number }) => {
128
+    const drawList: any[] = [];
129
+    let imagesTemp = images;
130
+
131
+    imagesTemp.forEach((image, index) => drawList.push(this._downloadImageAndInfo(image, index, pixelRatio)));
132
+
133
+    return Promise.all(drawList);
134
+  }
135
+
136
+  /**
137
+   * @param
138
+   */
139
+  downloadResourceTransit = () => {
140
+    const { config } = this.props;
141
+    return new Promise<any>((resolve, reject) => {
142
+      if (config.images && config.images.length > 0) {
143
+        this.downloadResource({
144
+          images: config.images,
145
+          pixelRatio: config.pixelRatio || 1,
146
+        })
147
+          .then(() => {
148
+            resolve();
149
+          })
150
+          .catch((e) => {
151
+            // console.log(e);
152
+            reject(e)
153
+          });
154
+      } else {
155
+        setTimeout(() => {
156
+          resolve(1);
157
+        }, 500)
158
+      }
159
+    })
160
+  }
161
+
162
+  initCanvas = (w, h, debug) => {
163
+    return new Promise<void>((resolve) => {
164
+      this.setState({
165
+        pxWidth: this.toPx(w),
166
+        pxHeight: this.toPx(h),
167
+        debug,
168
+      }, resolve);
169
+    });
170
+  }
171
+
172
+  onCreate = () => {
173
+    const { onCreateFail, config } = this.props;
174
+    if (config['hide-loading'] === false) {
175
+      Taro.showLoading({ mask: true, title: '生成中...' });
176
+    }
177
+    return this.downloadResourceTransit()
178
+      .then(() => {
179
+        this.create(config);
180
+      })
181
+      .catch((err) => {
182
+        config['hide-loading'] && Taro.hideLoading();
183
+        Taro.showToast({ icon: 'none', title: err.errMsg || '下载图片失败' });
184
+        console.error(err);
185
+        if (!onCreateFail) {
186
+          console.warn('您必须实现 taro-plugin-canvas 组件的 onCreateFail 方法,详见文档 https://github.com/chuyun/taro-plugin-canvas#fail');
187
+        }
188
+        onCreateFail && onCreateFail(err);
189
+      })
190
+  }
191
+
192
+  create = (config) => {
193
+    this.ctx = Taro.createCanvasContext(this.canvasId, this.$scope);
194
+    const height = getHeight(config);
195
+    // 设置 pixelRatio
196
+    this.setState({
197
+      pixelRatio: config.pixelRatio || 1,
198
+    }, () => {
199
+      this.initCanvas(config.width, height, config.debug)
200
+        .then(() => {
201
+          // 设置画布底色
202
+          if (config.backgroundColor) {
203
+            this.ctx!.save();
204
+            this.ctx!.setFillStyle(config.backgroundColor);
205
+            this.ctx!.fillRect(0, 0, this.toPx(config.width), this.toPx(height));
206
+            this.ctx!.restore();
207
+          }
208
+          const {
209
+            texts = [],
210
+            // images = [],
211
+            blocks = [],
212
+            lines = [],
213
+          } = config;
214
+          const queue = this.drawArr
215
+            .concat(texts.map((item) => {
216
+              item.type = 'text';
217
+              item.zIndex = item.zIndex || 0;
218
+              return item;
219
+            }))
220
+            .concat(blocks.map((item) => {
221
+              item.type = 'block';
222
+              item.zIndex = item.zIndex || 0;
223
+              return item;
224
+            }))
225
+            .concat(lines.map((item) => {
226
+              item.type = 'line';
227
+              item.zIndex = item.zIndex || 0;
228
+              return item;
229
+            }));
230
+          // 按照顺序排序
231
+          queue.sort((a, b) => a.zIndex - b.zIndex);
232
+
233
+          queue.forEach((item) => {
234
+            let drawOptions = {
235
+              ctx: (this.ctx as CanvasContext),
236
+              toPx: this.toPx,
237
+              toRpx: this.toRpx,
238
+            }
239
+            if (item.type === 'image') {
240
+              if (drawOptions.ctx !== null) {
241
+                drawImage(item, drawOptions);
242
+              }
243
+            } else if (item.type === 'text') {
244
+              if (drawOptions.ctx !== null) {
245
+                drawText(item, drawOptions)
246
+              }
247
+            } else if (item.type === 'block') {
248
+              if (drawOptions.ctx !== null) {
249
+                drawBlock(item, drawOptions)
250
+              }
251
+
252
+            } else if (item.type === 'line') {
253
+              if (drawOptions.ctx !== null) {
254
+                drawLine(item, drawOptions)
255
+              }
256
+            }
257
+          });
258
+
259
+          const res = Taro.getSystemInfoSync();
260
+          const platform = res.platform;
261
+          let time = 0;
262
+          if (platform === 'android') {
263
+            // 在安卓平台,经测试发现如果海报过于复杂在转换时需要做延时,要不然样式会错乱
264
+            time = 300;
265
+          }
266
+          this.ctx!.draw(false, () => {
267
+            setTimeout(() => {
268
+              this.getTempFile(null);
269
+            }, time);
270
+          });
271
+        })
272
+        .catch((err) => {
273
+          Taro.showToast({ icon: 'none', title: err.errMsg || '生成失败' });
274
+          console.error(err);
275
+        });
276
+    });
277
+
278
+  }
279
+
280
+  getTempFile = (otherOptions) => {
281
+    const { onCreateSuccess, onCreateFail } = this.props;
282
+    Taro.canvasToTempFilePath({
283
+      canvasId: this.canvasId,
284
+      success: (result) => {
285
+        if (!onCreateSuccess) {
286
+          console.warn('您必须实现 taro-plugin-canvas 组件的 onCreateSuccess 方法,详见文档 https://github.com/chuyun/taro-plugin-canvas#success');
287
+        }
288
+        onCreateSuccess && onCreateSuccess(result);
289
+      },
290
+      fail: (error) => {
291
+        const { errMsg } = error;
292
+        console.log(errMsg)
293
+        if (errMsg === 'canvasToTempFilePath:fail:create bitmap failed') {
294
+          count += 1;
295
+          if (count <= 3) {
296
+            this.getTempFile(otherOptions);
297
+          } else {
298
+            if (!onCreateFail) {
299
+              console.warn('您必须实现 taro-plugin-canvas 组件的 onCreateFail 方法,详见文档 https://github.com/chuyun/taro-plugin-canvas#fail');
300
+            }
301
+            onCreateFail && onCreateFail(error);
302
+          }
303
+        }
304
+      },
305
+    }, this.$scope);
306
+  }
307
+
308
+  render() {
309
+    const { pxWidth, pxHeight, debug } = this.state;
310
+    if (pxWidth && pxHeight) {
311
+      return (
312
+        <Canvas
313
+          canvasId={this.canvasId}
314
+          style={`width:${pxWidth}px; height:${pxHeight}px;`}
315
+          className={`${debug ? 'debug' : 'pro'} canvas`}
316
+        />
317
+      );
318
+    }
319
+    return null;
320
+  }
321
+}
322
+

+ 84 - 0
src/component/taro-plugin-canvas/types.ts

@@ -0,0 +1,84 @@
1
+
2
+export interface IConfig {
3
+  width: number;
4
+  height: number;
5
+  backgroundColor?: string;
6
+  debug?: boolean;
7
+  pixelRatio?: number;
8
+  preload?: boolean;
9
+  'hide-loading'?: boolean;
10
+  blocks?: IBlock[];
11
+  texts?: IText[];
12
+  images?: IIMage[];
13
+  lines?: ILine[];
14
+}
15
+
16
+
17
+export interface IBlock {
18
+  x: number;
19
+  y: number;
20
+  width?: number;
21
+  height: number;
22
+  paddingLeft?: number;
23
+  paddingRight?: number;
24
+  borderWidth?: number;
25
+  borderColor?: string;
26
+  backgroundColor?: string;
27
+  borderRadius?: number;
28
+  text?: IText;
29
+  opacity?: number;
30
+  zIndex?: number;
31
+}
32
+
33
+export interface IText {
34
+  x: number;
35
+  y: number;
36
+  text: string | {
37
+    text: string;
38
+    marginLeft: number;
39
+    marginRight: number;
40
+  };
41
+  fontSize: number;
42
+  color?: string;
43
+  opacity?: 1 | 0;
44
+  lineHeight?: number;
45
+  lineNum?: number;
46
+  width?: number;
47
+  marginLeft?: number;
48
+  marginRight?: number;
49
+  textDecoration?: 'line-through' | 'none';
50
+  baseLine?: 'top' | 'middle' | 'bottom';
51
+  textAlign?: 'left' | 'center' | 'right';
52
+  fontFamily?: string;
53
+  fontWeight?: string;
54
+  fontStyle?: string;
55
+  zIndex?: number;
56
+}
57
+
58
+export interface IIMage {
59
+  x: number;
60
+  y: number;
61
+  url: string;
62
+  width: number;
63
+  height: number;
64
+  borderRadius?: number;
65
+  borderWidth?: number;
66
+  borderColor?: string;
67
+  zIndex?: number;
68
+}
69
+
70
+export interface ILine {
71
+  startX: number;
72
+  startY: number;
73
+  endX: number;
74
+  endY: number;
75
+  width: number;
76
+  color?: string;
77
+  zIndex?: number;
78
+}
79
+
80
+export type IDrawType = 'text' | 'image' | 'block' | 'line';
81
+
82
+export type IDrawArrayItem = {
83
+  type?: IDrawType;
84
+} & (ILine | IIMage | IBlock | IText);

+ 394 - 0
src/component/taro-plugin-canvas/utils/draw.ts

@@ -0,0 +1,394 @@
1
+
2
+import { CanvasContext } from "@tarojs/taro";
3
+import { IText, IIMage, ILine, IBlock } from '../types';
4
+
5
+export interface IDrawRadiusRectData {
6
+  x: number;
7
+  y: number;
8
+  w: number;
9
+  h: number;
10
+  r: number;
11
+}
12
+
13
+export interface IDrawOptions {
14
+  ctx: CanvasContext;
15
+  toPx: (rpx: number, int?: boolean, factor?: number) => number;
16
+  toRpx: (px: number, int?: boolean, factor?: number) => number;
17
+}
18
+
19
+/**
20
+  * @description 绘制圆角矩形
21
+  * @param { object } drawData - 绘制数据
22
+  * @param { number } drawData.x - 左上角x坐标
23
+  * @param { number } drawData.y - 左上角y坐标
24
+  * @param { number } drawData.w - 矩形的宽
25
+  * @param { number } drawData.h - 矩形的高
26
+  * @param { number } drawData.r - 圆角半径
27
+  */
28
+export function _drawRadiusRect(drawData: IDrawRadiusRectData, drawOptions: IDrawOptions) {
29
+  const { x, y, w, h, r } = drawData;
30
+  const {
31
+    ctx,
32
+    toPx,
33
+    // toRpx,
34
+  } = drawOptions;
35
+  const br = r / 2;
36
+  ctx.beginPath();
37
+  ctx.moveTo(toPx(x + br), toPx(y));    // 移动到左上角的点
38
+  ctx.lineTo(toPx(x + w - br), toPx(y));
39
+  ctx.arc(toPx(x + w - br), toPx(y + br), toPx(br), 2 * Math.PI * (3 / 4), 2 * Math.PI * (4 / 4))
40
+  ctx.lineTo(toPx(x + w), toPx(y + h - br));
41
+  ctx.arc(toPx(x + w - br), toPx(y + h - br), toPx(br), 0, 2 * Math.PI * (1 / 4))
42
+  ctx.lineTo(toPx(x + br), toPx(y + h));
43
+  ctx.arc(toPx(x + br), toPx(y + h - br), toPx(br), 2 * Math.PI * (1 / 4), 2 * Math.PI * (2 / 4))
44
+  ctx.lineTo(toPx(x), toPx(y + br));
45
+  ctx.arc(toPx(x + br), toPx(y + br), toPx(br), 2 * Math.PI * (2 / 4), 2 * Math.PI * (3 / 4))
46
+}
47
+
48
+
49
+/**
50
+ * @description 计算文本长度
51
+ * @param { Array | Object } text 数组 或者 对象
52
+ */
53
+export function _getTextWidth(_text: IText | IText[], drawOptions: IDrawOptions): number {
54
+  const { ctx, toPx, toRpx } = drawOptions;
55
+  let texts: IText[] = [];
56
+  if (Array.isArray(_text)) {
57
+    texts = _text;
58
+  } else {
59
+    texts.push(_text);
60
+  }
61
+  let width = 0;
62
+  texts.forEach(({
63
+    fontSize,
64
+    text,
65
+    marginLeft = 0,
66
+    marginRight = 0
67
+  }) => {
68
+    ctx.setFontSize(toPx(fontSize));
69
+    let _textWidth = 0;
70
+    if (typeof text === 'object') {
71
+      _textWidth = ctx.measureText(text.text).width + text.marginLeft + text.marginRight;
72
+    } else {
73
+      _textWidth = ctx.measureText(text).width;
74
+    }
75
+    width += _textWidth + marginLeft + marginRight;
76
+  })
77
+  return toRpx(width);
78
+}
79
+
80
+
81
+/**
82
+  * @description 渲染一段文字
83
+  * @param { object } drawData - 绘制数据
84
+  * @param { number } drawData.x - x坐标 rpx
85
+  * @param { number } drawData.y - y坐标 rpx
86
+  * @param { number } drawData.fontSize - 文字大小 rpx
87
+  * @param { number } [drawData.color] - 颜色
88
+  * @param { string } [drawData.baseLine] - 基线对齐方式 top| middle|bottom
89
+  * @param { string } [drawData.textAlign='left'] - 对齐方式 left|center|right
90
+  * @param { string } drawData.text - 当Object类型时,参数为 text 字段的参数,marginLeft、marginRight这两个字段可用
91
+  * @param { number } [drawData.opacity=1] - 1为不透明,0为透明
92
+  * @param { string } [drawData.textDecoration='none']
93
+  * @param { number } [drawData.width] - 文字宽度 没有指定为画布宽度
94
+  * @param { number } [drawData.lineNum=1] - 根据宽度换行,最多的行数
95
+  * @param { number } [drawData.lineHeight=0] - 行高
96
+  * @param { string } [drawData.fontWeight='normal'] - 'bold' 加粗字体,目前小程序不支持 100 - 900 加粗
97
+  * @param { string } [drawData.fontStyle='normal'] - 'italic' 倾斜字体
98
+  * @param { string } [drawData.fontFamily="sans-serif"] - 小程序默认字体为 'sans-serif', 请输入小程序支持的字体
99
+  */
100
+
101
+interface IDrawSingleTextData extends IText {
102
+}
103
+export function _drawSingleText(drawData: IDrawSingleTextData, drawOptions: IDrawOptions) {
104
+  let { x, y, fontSize, color, baseLine, textAlign = 'left', text, opacity = 1, textDecoration = 'none',
105
+    width = 0, lineNum = 1, lineHeight = 0, fontWeight = 'normal', fontStyle = 'normal', fontFamily = "sans-serif" } = drawData;
106
+  const { ctx, toPx } = drawOptions;
107
+  ctx.save();
108
+  ctx.beginPath();
109
+  ctx.font = fontStyle + " " + fontWeight + " " + toPx(fontSize, true) + "px " + fontFamily
110
+  ctx.setGlobalAlpha(opacity);
111
+  // ctx.setFontSize(toPx(fontSize));
112
+  if (typeof text === 'object') {
113
+    text = text.text
114
+  }
115
+
116
+  color && ctx.setFillStyle(color);
117
+  baseLine && ctx.setTextBaseline(baseLine);
118
+  ctx.setTextAlign(textAlign);
119
+  let textWidth = (ctx.measureText(text as string).width);
120
+  const textArr: string[] = [];
121
+  let drawWidth = toPx(width);
122
+  if (width && textWidth > drawWidth) {
123
+    // 文本宽度 大于 渲染宽度
124
+    let fillText = '';
125
+    let line = 1;
126
+    for (let i = 0; i <= (text as string).length - 1; i++) {  // 将文字转为数组,一行文字一个元素
127
+      fillText = fillText + text[i];
128
+      if ((ctx.measureText(fillText).width) >= drawWidth) {
129
+        if (line === lineNum) {
130
+          if (i !== (text as string).length - 1) {
131
+            fillText = fillText.substring(0, fillText.length - 1) + '...';
132
+          }
133
+        }
134
+        if (line <= lineNum) {
135
+          textArr.push(fillText);
136
+        }
137
+        fillText = '';
138
+        line++;
139
+      } else {
140
+        if (line <= lineNum) {
141
+          if (i === (text as string).length - 1) {
142
+            textArr.push(fillText);
143
+          }
144
+        }
145
+      }
146
+    }
147
+    textWidth = width;
148
+  } else {
149
+    textArr.push(text as string);
150
+  }
151
+
152
+  textArr.forEach((item, index) => {
153
+    ctx.fillText(item, toPx(x), toPx(y + (lineHeight || fontSize) * index));
154
+  })
155
+  ctx.restore();
156
+  // textDecoration
157
+  if (textDecoration !== 'none') {
158
+    let lineY = y;
159
+    if (textDecoration === 'line-through') {
160
+      // 目前只支持贯穿线
161
+      lineY = y;
162
+      // 小程序画布baseLine偏移阈值
163
+      let threshold = 5;
164
+
165
+      // 根据baseLine的不同对贯穿线的Y坐标做相应调整
166
+      switch (baseLine) {
167
+        case 'top':
168
+          lineY += fontSize / 2 + threshold;
169
+          break;
170
+        case 'middle':
171
+          break;
172
+        case 'bottom':
173
+          lineY -= fontSize / 2 + threshold;
174
+          break;
175
+        default:
176
+          lineY -= fontSize / 2 - threshold;
177
+          break;
178
+      }
179
+    }
180
+    ctx.save();
181
+    ctx.moveTo(toPx(x), toPx(lineY));
182
+    ctx.lineTo(toPx(x) + toPx(textWidth), toPx(lineY));
183
+    color && ctx.setStrokeStyle(color);
184
+    ctx.stroke();
185
+    ctx.restore();
186
+  }
187
+  return textWidth;
188
+}
189
+
190
+/**
191
+ * 渲染文字
192
+ * @param { object } params - 绘制数据
193
+ * @param { number } params.x - x坐标 rpx
194
+ * @param { number } params.y - y坐标 rpx
195
+ * @param { number } params.fontSize - 文字大小 rpx
196
+ * @param { number } [params.color] - 颜色
197
+ * @param { string } [params.baseLine] - 基线对齐方式 top| middle|bottom
198
+ * @param { string } [params.textAlign='left'] - 对齐方式 left|center|right
199
+ * @param { string } params.text - 当Object类型时,参数为 text 字段的参数,marginLeft、marginRight这两个字段可用
200
+ * @param { number } [params.opacity=1] - 1为不透明,0为透明
201
+ * @param { string } [params.textDecoration='none']
202
+ * @param { number } [params.width] - 文字宽度 没有指定为画布宽度
203
+ * @param { number } [params.lineNum=1] - 根据宽度换行,最多的行数
204
+ * @param { number } [params.lineHeight=0] - 行高
205
+ * @param { string } [params.fontWeight='normal'] - 'bold' 加粗字体,目前小程序不支持 100 - 900 加粗
206
+ * @param { string } [params.fontStyle='normal'] - 'italic' 倾斜字体
207
+ * @param { string } [params.fontFamily="sans-serif"] - 小程序默认字体为 'sans-serif', 请输入小程序支持的字体
208
+ */
209
+export function drawText(params: IText, drawOptions: IDrawOptions) {
210
+  // const { ctx, toPx, toRpx } = drawOptions;
211
+  const {
212
+    x,
213
+    y, text, baseLine,
214
+    // fontSize,
215
+    // color,
216
+    // textAlign,
217
+    // opacity = 1,
218
+    // width,
219
+    // lineNum,
220
+    // lineHeight
221
+  } = params;
222
+  if (Array.isArray(text)) {
223
+    let preText = { x, y, baseLine };
224
+    text.forEach(item => {
225
+      preText.x += item.marginLeft || 0;
226
+      const textWidth = _drawSingleText(Object.assign(item, {
227
+        ...preText,
228
+      }), drawOptions);
229
+      preText.x += textWidth + (item.marginRight || 0); // 下一段字的 x 轴为上一段字 x + 上一段字宽度
230
+    })
231
+  } else {
232
+    _drawSingleText(params, drawOptions);
233
+  }
234
+}
235
+
236
+export interface IDrawImageData extends IIMage {
237
+  imgPath: string;
238
+  w: number;
239
+  h: number;
240
+  sx: number;
241
+  sy: number;
242
+  sw: number;
243
+  sh: number;
244
+}
245
+
246
+/**
247
+ * @description 渲染图片
248
+ * @param { object } data
249
+ * @param { number } x - 图像的左上角在目标 canvas 上 x 轴的位置
250
+ * @param { number } y - 图像的左上角在目标 canvas 上 y 轴的位置
251
+ * @param { number } w - 在目标画布上绘制图像的宽度,允许对绘制的图像进行缩放
252
+ * @param { number } h - 在目标画布上绘制图像的高度,允许对绘制的图像进行缩放
253
+ * @param { number } sx - 源图像的矩形选择框的左上角 x 坐标
254
+ * @param { number } sy - 源图像的矩形选择框的左上角 y 坐标
255
+ * @param { number } sw - 源图像的矩形选择框的宽度
256
+ * @param { number } sh - 源图像的矩形选择框的高度
257
+ * @param { number } [borderRadius=0] - 圆角
258
+ * @param { number } [borderWidth=0] - 边框
259
+ */
260
+export function drawImage(data: IDrawImageData, drawOptions: IDrawOptions) {
261
+  const { ctx, toPx } = drawOptions;
262
+  const { imgPath, x, y, w, h, sx, sy, sw, sh, borderRadius = 0, borderWidth = 0, borderColor } = data;
263
+  ctx.save();
264
+  if (borderRadius > 0) {
265
+    let drawData = {
266
+      x, y, w, h,
267
+      r: borderRadius
268
+    };
269
+    _drawRadiusRect(drawData, drawOptions);
270
+    ctx.strokeStyle = 'rgba(255,255,255,0)';
271
+    ctx.stroke();
272
+    ctx.clip();
273
+    ctx.drawImage(imgPath, toPx(sx), toPx(sy), toPx(sw), toPx(sh), toPx(x), toPx(y), toPx(w), toPx(h));
274
+    if (borderWidth > 0) {
275
+      borderColor && ctx.setStrokeStyle(borderColor);
276
+      ctx.setLineWidth(toPx(borderWidth));
277
+      ctx.stroke();
278
+    }
279
+  } else {
280
+    ctx.drawImage(imgPath, toPx(sx), toPx(sy), toPx(sw), toPx(sh), toPx(x), toPx(y), toPx(w), toPx(h));
281
+  }
282
+  ctx.restore();
283
+}
284
+
285
+/**
286
+ * @description 渲染线
287
+ * @param  { number } startX - 起始坐标
288
+ * @param  { number } startY - 起始坐标
289
+ * @param  { number } endX - 终结坐标
290
+ * @param  { number } endY - 终结坐标
291
+ * @param  { number } width - 线的宽度
292
+ * @param  { string } [color] - 线的颜色
293
+ */
294
+export function drawLine(drawData: ILine, drawOptions: IDrawOptions) {
295
+  const { startX, startY, endX, endY, color, width } = drawData;
296
+  const { ctx, toPx } = drawOptions;
297
+  ctx.save();
298
+  ctx.beginPath();
299
+  color && ctx.setStrokeStyle(color);
300
+  ctx.setLineWidth(toPx(width));
301
+  ctx.moveTo(toPx(startX), toPx(startY));
302
+  ctx.lineTo(toPx(endX), toPx(endY));
303
+  ctx.stroke();
304
+  ctx.closePath();
305
+  ctx.restore();
306
+}
307
+
308
+/**
309
+* @description 渲染块
310
+* @param  { number } x - x坐标
311
+* @param  { number } y - y坐标
312
+* @param  { number } height -高
313
+* @param  { string|object } [text] - 块里面可以填充文字,参考texts字段
314
+* @param  { number } [width=0] - 宽 如果内部有文字,由文字宽度和内边距决定
315
+* @param  { number } [paddingLeft=0] - 内左边距
316
+* @param  { number } [paddingRight=0] - 内右边距
317
+* @param  { number } [borderWidth] - 边框宽度
318
+* @param  { string } [backgroundColor] - 背景颜色
319
+* @param  { string } [borderColor] - 边框颜色
320
+* @param  { number } [borderRadius=0] - 圆角
321
+* @param  { number } [opacity=1] - 透明度
322
+*
323
+*/
324
+export function drawBlock(blockData: IBlock, drawOptions: IDrawOptions) {
325
+  const { ctx, toPx, } = drawOptions;
326
+  const { text, width = 0, height, x, y, paddingLeft = 0, paddingRight = 0, borderWidth, backgroundColor, borderColor, borderRadius = 0, opacity = 1 } = blockData;
327
+  // 判断是否块内有文字
328
+  let blockWidth = 0; // 块的宽度
329
+  let textX = 0;
330
+  let textY = 0;
331
+  if (typeof text !== 'undefined') {
332
+    // 如果有文字并且块的宽度小于文字宽度,块的宽度为 文字的宽度 + 内边距
333
+    // const textWidth = _getTextWidth(typeof text.text === 'string' ? text : text.text, drawOptions);
334
+    const textWidth: number = _getTextWidth(text, drawOptions);
335
+    blockWidth = textWidth > width ? textWidth : width;
336
+    blockWidth += paddingLeft + paddingLeft;
337
+
338
+    const {
339
+      textAlign = 'left',
340
+      // text: textCon,
341
+    } = text;
342
+    textY = height / 2 + y; // 文字的y轴坐标在块中线
343
+    if (textAlign === 'left') {
344
+      // 如果是右对齐,那x轴在块的最左边
345
+      textX = x + paddingLeft;
346
+    } else if (textAlign === 'center') {
347
+      textX = blockWidth / 2 + x;
348
+    } else {
349
+      textX = x + blockWidth - paddingRight;
350
+    }
351
+  } else {
352
+    blockWidth = width;
353
+  }
354
+
355
+  if (backgroundColor) {
356
+    // 画面
357
+    ctx.save();
358
+    ctx.setGlobalAlpha(opacity);
359
+    ctx.setFillStyle(backgroundColor);
360
+    if (borderRadius > 0) {
361
+      // 画圆角矩形
362
+      let drawData = {
363
+        x, y, w: blockWidth, h: height, r: borderRadius
364
+      };
365
+      _drawRadiusRect(drawData, drawOptions);
366
+      ctx.fill();
367
+    } else {
368
+      ctx.fillRect(toPx(x), toPx(y), toPx(blockWidth), toPx(height));
369
+    }
370
+    ctx.restore();
371
+  }
372
+  if (borderWidth) {
373
+    // 画线
374
+    ctx.save();
375
+    ctx.setGlobalAlpha(opacity);
376
+    borderColor && ctx.setStrokeStyle(borderColor);
377
+    ctx.setLineWidth(toPx(borderWidth));
378
+    if (borderRadius > 0) {
379
+      // 画圆角矩形边框
380
+      let drawData = {
381
+        x, y, w: blockWidth, h: height, r: borderRadius,
382
+      }
383
+      _drawRadiusRect(drawData, drawOptions);
384
+      ctx.stroke();
385
+    } else {
386
+      ctx.strokeRect(toPx(x), toPx(y), toPx(blockWidth), toPx(height));
387
+    }
388
+    ctx.restore();
389
+  }
390
+
391
+  if (text) {
392
+    drawText(Object.assign(text, { x: textX, y: textY }), drawOptions)
393
+  }
394
+}

+ 204 - 0
src/component/taro-plugin-canvas/utils/tools.ts

@@ -0,0 +1,204 @@
1
+import Taro from '@tarojs/taro';
2
+import { IConfig } from '../types';
3
+/**
4
+ * @description 生成随机字符串
5
+ * @param  { number } length - 字符串长度
6
+ * @returns { string }
7
+ */
8
+export const randomString = (length: number) => {
9
+  let str = Math.random().toString(36).substr(2);
10
+  if (str.length >= length) {
11
+    return str.substr(0, length);
12
+  }
13
+  str += randomString(length - str.length);
14
+  return str;
15
+}
16
+
17
+/**
18
+ * @description 获取最大高度
19
+ * @param  {} config
20
+ * @returns { number }
21
+ */
22
+export const getHeight = (config: IConfig) => {
23
+  const getTextHeight = (text) => {
24
+    let fontHeight = text.lineHeight || text.fontSize;
25
+    let height = 0;
26
+    if (text.baseLine === 'top') {
27
+      height = fontHeight;
28
+    } else if (text.baseLine === 'middle') {
29
+      height = fontHeight / 2;
30
+    } else {
31
+      height = 0;
32
+    }
33
+    return height;
34
+  }
35
+  const heightArr: number[] = [];
36
+  (config.blocks || []).forEach((item) => {
37
+    heightArr.push(item.y + item.height);
38
+  });
39
+  (config.texts || []).forEach((item) => {
40
+    let height;
41
+    height = getTextHeight(item);
42
+    heightArr.push(item.y + height);
43
+  });
44
+  (config.images || []).forEach((item) => {
45
+    heightArr.push(item.y + item.height);
46
+  });
47
+  (config.lines || []).forEach((item) => {
48
+    heightArr.push(item.startY);
49
+    heightArr.push(item.endY);
50
+  });
51
+  const sortRes = heightArr.sort((a, b) => b - a);
52
+  let canvasHeight = 0;
53
+  if (sortRes.length > 0) {
54
+    canvasHeight = sortRes[0];
55
+  }
56
+  if (config.height < canvasHeight || !config.height) {
57
+    return canvasHeight;
58
+  } else {
59
+    return config.height;
60
+  }
61
+}
62
+
63
+
64
+/**
65
+ * 将http转为https
66
+ * @param {String}} rawUrl 图片资源url
67
+ * @returns { string }
68
+ */
69
+export function mapHttpToHttps(rawUrl: string) {
70
+  if (rawUrl.indexOf(':') < 0) {
71
+    return rawUrl;
72
+  }
73
+  const urlComponent = rawUrl.split(':');
74
+  if (urlComponent.length === 2) {
75
+    if (urlComponent[0] === 'http') {
76
+      urlComponent[0] = 'https';
77
+      return `${urlComponent[0]}:${urlComponent[1]}`;
78
+    }
79
+  }
80
+  return rawUrl;
81
+}
82
+
83
+/**
84
+ * 下载图片资源
85
+ * @param { string } imageUrl
86
+ * @returns  { Promise }
87
+ */
88
+export function downImage(imageUrl: string) {
89
+  return new Promise<string>((resolve, reject) => {
90
+    // if (/^http/.test(imageUrl) && !new RegExp(wx.env.USER_DATA_PATH).test(imageUrl))
91
+    if (
92
+      /^http/.test(imageUrl) &&
93
+      // @ts-ignore
94
+      !new RegExp((wx as any).env.USER_DATA_PATH).test(imageUrl) &&
95
+      !/^http:\/\/tmp/.test(imageUrl)
96
+    ) {
97
+      Taro.downloadFile({
98
+        url: (imageUrl),
99
+        // TODO
100
+        // url: mapHttpToHttps(imageUrl),
101
+        success: (res) => {
102
+          if (res.statusCode === 200) {
103
+            resolve(res.tempFilePath);
104
+          } else {
105
+            reject(res.errMsg);
106
+          }
107
+        },
108
+        fail(err) {
109
+          reject(err);
110
+        },
111
+      });
112
+    } else {
113
+      // 支持本地地址
114
+      resolve(imageUrl);
115
+    }
116
+  });
117
+}
118
+
119
+export interface IMageInfo {
120
+  imgPath: string;
121
+  imgInfo: any;
122
+  index: number | string;
123
+}
124
+
125
+
126
+/**
127
+ * 获取图片信息
128
+ * @param {*} imgPath
129
+ * @param {*} index
130
+ * @returns  { Promise }
131
+ */
132
+export function getImageInfo(imgPath: string, index: string) {
133
+  return new Promise<IMageInfo>((resolve, reject) => {
134
+    Taro.getImageInfo({
135
+      src: imgPath
136
+    })
137
+      .then(res => {
138
+        resolve({
139
+          imgPath,
140
+          imgInfo: res,
141
+          index
142
+        });
143
+      })
144
+      .catch(err => {
145
+        reject(err);
146
+      })
147
+  });
148
+}
149
+
150
+/**
151
+* @description 下载图片并获取图片信息
152
+* @param  {} image
153
+* @param  {} index
154
+* @returns  { Promise }
155
+*/
156
+export function downloadImageAndInfo(image, index, toRpxFunc, pixelRatio) {
157
+  return new Promise<any>((resolve, reject) => {
158
+    const { x, y, url, zIndex } = image;
159
+    const imageUrl = url;
160
+    // 下载图片
161
+    downImage(imageUrl)
162
+      // 获取图片信息
163
+      .then(imgPath => getImageInfo(imgPath, index))
164
+      .then(({ imgPath, imgInfo }) => {
165
+        // 根据画布的宽高计算出图片绘制的大小,这里会保证图片绘制不变形
166
+        let sx;
167
+        let sy;
168
+        const borderRadius = image.borderRadius || 0;
169
+        const setWidth = image.width;
170
+        const setHeight = image.height;
171
+        const width = toRpxFunc(imgInfo.width / pixelRatio);
172
+        const height = toRpxFunc(imgInfo.height / pixelRatio);
173
+
174
+        if (width / height <= setWidth / setHeight) {
175
+          sx = 0;
176
+          sy = (height - ((width / setWidth) * setHeight)) / 2;
177
+        } else {
178
+          sy = 0;
179
+          sx = (width - ((height / setHeight) * setWidth)) / 2;
180
+        }
181
+        let result = {
182
+          type: 'image',
183
+          borderRadius,
184
+          borderWidth: image.borderWidth,
185
+          borderColor: image.borderColor,
186
+          zIndex: typeof zIndex !== 'undefined' ? zIndex : index,
187
+          imgPath,
188
+          sx,
189
+          sy,
190
+          sw: (width - (sx * 2)),
191
+          sh: (height - (sy * 2)),
192
+          x,
193
+          y,
194
+          w: setWidth,
195
+          h: setHeight,
196
+        }
197
+        resolve(result);
198
+      })
199
+      .catch(err => {
200
+        console.log(err);
201
+        reject(err)
202
+      });
203
+  });
204
+}

BIN
src/images/nav/like.png


BIN
src/images/nav/like_pin.png


BIN
src/images/nav/play_pin.png


+ 5 - 0
src/index.html

@@ -9,6 +9,11 @@
9 9
   <meta name="apple-mobile-web-app-status-bar-style" content="white">
10 10
   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" >
11 11
   <title>myApp</title>
12
+  <style>
13
+    page{
14
+      background-color: #041129;
15
+    }
16
+  </style>
12 17
   <script><%= htmlWebpackPlugin.options.script %></script>
13 18
 </head>
14 19
 <body>

+ 3 - 1
src/pages/collection/index.config.js

@@ -1,3 +1,5 @@
1 1
 export default definePageConfig({
2
-  navigationBarTitleText: '首页'
2
+  navigationBarTitleText: '社区',
3
+  enableShareAppMessage: true,
4
+  enableShareTimeline: true ,
3 5
 })

+ 146 - 12
src/pages/collection/index.jsx

@@ -1,24 +1,158 @@
1 1
 import { Component } from 'react'
2 2
 import { View, Text, Button, Image, scrollView, Input } from '@tarojs/components'
3
+import * as api from '../../service/index'
4
+import tool from '../../common/tool'
5
+import Taro, { } from '@tarojs/taro'
3 6
 import './index.less'
4 7
 
5 8
 export default class collection extends Component {
9
+  state = {
10
+    tableIndex: 0,
11
+    total: false,
12
+    page: 1,
13
+    page_size: 20,
14
+    cardinalInfos: [],//基数
15
+    evenInfos: [],//偶数
16
+    type: 'hot',//hot:热门,time:最新
17
+  }
6 18
 
7
-  componentWillMount() { }
8
-
9
-  componentDidMount() { }
10
-
11
-  componentWillUnmount() { }
12
-
13
-  componentDidShow() { }
19
+  componentWillMount () {
20
+    // this.setInit(1, 'hot')
21
+  }
22
+  componentDidShow(){
23
+    this.setInit(1, 'hot')
24
+  }
25
+  setInit (page, type) {
26
+    this.setState({
27
+      total: false,//是否加载完
28
+      page: 1,
29
+      page_size: 20,
30
+      cardinalInfos: [],//基数
31
+      evenInfos: [],//偶数
32
+    })
33
+    this.getHubList(page, type)
34
+  }
35
+  onShareAppMessage = (res) => {
36
+    let shareData = {
37
+      title:tool.shareTitle,
38
+      path: `/pages/index/index?c=${Taro.getStorageSync('user_id')}&s=rightTap`,
39
+      imageUrl: tool.shareImg
40
+    }
41
+    return shareData;
42
+  }
14 43
 
15
-  componentDidHide() { }
44
+  getHubList (page, type) {
45
+    let params = {
46
+      page: page,
47
+      page_size: this.state.page_size,
48
+      otype: type
49
+    }
50
+    Taro.showLoading({
51
+      title: '加载中',
52
+    })
53
+    api.getHubList(params).then(res => {
54
+      if (res.code == 200) {
55
+        Taro.hideLoading()
56
+        let _evenInfos = res.data.filter((item, index) => {
57
+          return index % 2 == 1
58
+        })
59
+        let _cardinalInfos = res.data.filter((item, index) => {
60
+          return index % 2 == 0
61
+        })
62
+        console.log(_cardinalInfos, '_cardinalInfos');
63
+        let cardinalInfos = this.state.cardinalInfos.concat(_cardinalInfos)
64
+        let evenInfos = this.state.evenInfos.concat(_evenInfos)
65
+        this.setState({
66
+          cardinalInfos: cardinalInfos,//基数
67
+          evenInfos: evenInfos,//偶数
68
+          total: res.data.length < 20 ? true : false
69
+        })
70
+      }
71
+    })
72
+  }
73
+  onReachBottom () {
74
+    if (!this.state.total) {
75
+      this.setState({
76
+        page: this.state.page + 1
77
+      })
78
+      this.getHubList((this.state.page + 1), this.state.type)
79
+    }
80
+  }
81
+  componentDidHide () { }
82
+  changeTab (index) {
83
+    let _type = index == 0 ? 'hot' : 'time'
84
+    this.setState({
85
+      tableIndex: index,
86
+      type: _type
87
+    })
88
+    this.setInit(1, _type)
89
+  }
90
+  detail (item, index) {
91
+    console.log(item, 'item');
92
+    Taro.navigateTo({
93
+      url: `/pages/communityDetail/index?task_id=${item.id}`
94
+    })
95
+  }
16 96
 
17
-  render() {
97
+  render () {
18 98
     return (
19
-     <View>
20
-      collection
21
-     </View>
99
+      <View className='mine'>
100
+        <View className='table'>
101
+          <View className='table-info' onClick={e => (this.changeTab(0))} style={this.state.tableIndex == 0 ? 'font-size: 20px;color: #FFFFFF;border-bottom: 4px solid #0F84EC;' : ''}>热门</View>
102
+          <View className='table-info' onClick={e => (this.changeTab(1))} style={this.state.tableIndex == 1 ? 'font-size: 20px;color: #FFFFFF;border-bottom: 4px solid #0F84EC;' : ''}>最新</View>
103
+        </View>
104
+        <View className='image-list'>
105
+          <View className='list-left'>
106
+            {
107
+              this.state.cardinalInfos.map((item, index) => (
108
+                <View className='image-info' key={index} onClick={e => (this.detail(item, index))}>
109
+                  <View className='info-top'>
110
+                    <Image className='info-img' lazyLoad mode='widthFix' src={item.img}></Image>
111
+                  </View>
112
+                  <View className='info-bottom'>
113
+                    <View className='info-name'></View>
114
+                    <View className='info-tips'>
115
+                      <View className='info-tips-left'>
116
+                        <Image className='info-head-img' src={item.user_info.head_img}></Image>
117
+                        <View className='info-sampling'>{tool.ellipsis(item.user_info.user_name, 8)}</View>
118
+                      </View>
119
+                      <View className='info-tips-right'>
120
+                        <Image className='info-like-img' src={item.has_like == 0 ? 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679296882735.png' : 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679296893058.png'}></Image>
121
+                        <View className='like-num'>{item.like_cnt}</View>
122
+                      </View>
123
+                    </View>
124
+                  </View>
125
+                </View>
126
+              ))
127
+            }
128
+          </View>
129
+          <View className='list-right'>
130
+            {
131
+              this.state.evenInfos.map((item, index) => (
132
+                <View className='image-info' key={index} onClick={e => (this.detail(item, index))}>
133
+                  <View className='info-top'>
134
+                    <Image className='info-img' lazyLoad mode='widthFix' src={item.img}></Image>
135
+                  </View>
136
+                  <View className='info-bottom'>
137
+                    <View className='info-name'></View>
138
+                    <View className='info-tips'>
139
+                      <View className='info-tips-left'>
140
+                        <Image className='info-head-img' src={item.user_info.head_img}></Image>
141
+                        <View className='info-sampling'>{tool.ellipsis(item.user_info.user_name, 8)}</View>
142
+                      </View>
143
+                      <View className='info-tips-right'>
144
+                        <Image className='info-like-img' src={item.has_like == 0 ? 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679296882735.png' : 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679296893058.png'}></Image>
145
+                        <View className='like-num'>{item.like_cnt}</View>
146
+                      </View>
147
+                    </View>
148
+                  </View>
149
+                </View>
150
+              ))
151
+            }
152
+          </View>
153
+
154
+        </View>
155
+      </View>
22 156
     )
23 157
   }
24 158
 }

+ 94 - 378
src/pages/collection/index.less

@@ -1,379 +1,95 @@
1
-page {
2
-  background-color: #f2f2f2;
3
-  height: 100%;
4
-  padding: 0 auto;
5
-  margin: 0 auto;
6
-}
7
-.login{
8
-  z-index: 999;
9
-  position: fixed;
10
-  top: 300rpx;
11
-  height: 100rpx;
12
-  text-align: center;
13
-  line-height: 100rpx;
14
-  width: 400rpx;
15
-  left: 50%;
16
-  margin-left: -200rpx;
17
-  background: white;
18
-}
19
-.Phone{
20
-  top: 500rpx;
21
-  width: 400rpx;
22
-}
23
-.login_zz{
24
-  position: fixed;
25
-  left: 0;
26
-  top: 0;
27
-  width: 100%;
28
-  height: 100%;
29
-  z-index: 998;
30
-  
31
-background-color: rgba(0,0,0,0.5);
32
-}
33
-swiper {
34
-  height: 180rpx;
35
-}
36
- 
37
-swiper swiper-item .slide-image {
38
-  width: 100%;
39
-  height: 180rpx;
40
-}
41
- 
42
-.jia_img {
43
-  height: 80rpx;
44
-  width: 90rpx;
45
-}
46
- 
47
-.time {
48
-  text-align: center;
49
-  padding: 5rpx 20rpx 5rpx 20rpx;
50
-  border-radius: 10rpx;
51
-  display: block;
52
-  height: 38rpx;
53
-  line-height: 38rpx;
54
-  position: relative;
55
-  margin: 0 auto;
56
-  margin-bottom: 20rpx;
57
-  width: 90rpx;
58
-  color: white;
59
-  font-size: 26rpx;
60
-  background-color: #dedede;
61
-}
62
- 
63
-.tab {
64
-  bottom: 120rpx;
65
-}
66
- 
67
-.tab_1 {
68
-  position: fixed;
69
-  bottom: 50rpx;
70
-  width: 200rpx;
71
-  font-size: 26rpx;
72
-  left: 50%;
73
-  margin-left: -45rpx;
74
-  height: 100rpx;
75
-}
76
- 
77
-.tab_2 {
78
-  right: 30rpx;
79
-  position: fixed;
80
-}
81
- 
82
-/* 聊天 */
83
- 
84
-.my_right {
85
-  float: right;
86
-  margin-top: 30rpx;
87
-  position: relative;
88
-}
89
- 
90
-.my_audio {
91
-  height: 60rpx;
92
-  width: 60rpx;
93
-  z-index: 2;
94
-  position: relative;
95
-  top: 10rpx;
96
-  left: 20rpx;
97
-}
98
- 
99
-.you_left {
100
-  margin-top: 30rpx;
101
-  float: left;
102
-  position: relative;
103
-  padding-left: 5rpx;
104
-}
105
- 
106
-.new_img {
107
-  width: 85rpx;
108
-  height: 85rpx;
109
-  overflow: hidden;
110
-}
111
- 
112
-.page_r {
113
-  float: right;
114
-}
115
- 
116
-.new_txt {
117
-  min-width: 380rpx;
118
-  width: 460rpx;
119
-  word-break: break-all;
120
-}
121
- 
122
-.new_txt_my {
123
-  border-radius: 7rpx;
124
-  background: #9fe75a;
125
-  position: relative;
126
-  right: 30rpx;
127
-  padding: 17rpx 30rpx 17rpx 30rpx;
128
-  float: right;
129
-  border: 1px solid #d0d0d0;
130
-}
131
- 
132
-.new_txt_my .arrow {
133
-  position: absolute;
134
-  z-index: 2;
135
-  width: 40rpx;
136
-  right: -38rpx;
137
-}
138
- 
139
-.new_txt_my .arrow em {
140
-  position: absolute;
141
-  border-style: solid;
142
-  border-width: 15rpx;
143
-  border-color: transparent transparent transparent #d0d0d0;
144
-  top: 1rpx;
145
-}
146
- 
147
-.new_txt_my .arrow span {
148
-  position: absolute;
149
-  top: 5rpx;
150
-  border-style: solid;
151
-  border-width: 15rpx;
152
-  border-color: transparent transparent transparent #9fe75a;
153
-}
154
- 
155
-.new_txt_my_2 {
156
-  word-break: break-all;
157
-  border-radius: 7rpx;
158
-  background: #9fe75a;
159
-  min-width: 330rpx;
160
-  max-width: 530rpx;
161
-  padding: 17rpx 30rpx 17rpx 30rpx;
162
-  float: right;
163
-}
164
- 
165
-.new_txt_ai {
166
-  border-radius: 7rpx;
167
-  left: 20rpx;
168
-  background-color: #fff;
169
-  position: relative;
170
-  border: 1px solid #d0d0d0;
171
-  float: left;
172
-}
173
- 
174
-.new_txt_ai .arrow {
175
-  position: relative;
176
-  width: 40rpx;
177
-  left: -30rpx;
178
-}
179
- 
180
-.new_txt_ai .arrow em {
181
-  position: absolute;
182
-  border-style: solid;
183
-  border-width: 15rpx;
184
-  top: 20rpx;
185
-  border-color: transparent #d0d0d0 transparent transparent;
186
-}
187
- 
188
-.new_txt_ai .arrow span {
189
-  position: absolute;
190
-  top: 20rpx;
191
-  border-style: solid;
192
-  border-width: 15rpx;
193
-  border-color: transparent #fff transparent transparent;
194
-  left: 2rpx;
195
-}
196
- 
197
-.ai_content {
198
-  word-break: break-all;
199
-  padding: 17rpx 30rpx 17rpx 30rpx;
200
-}
201
- 
202
-.sanjiao {
203
-  top: 25rpx;
204
-  position: relative;
205
-  width: 0px;
206
-  height: 0px;
207
-  border-width: 15rpx;
208
-  border-style: solid;
209
-}
210
- 
211
-.my {
212
-  border-color: transparent transparent transparent #9fe75a;
213
-}
214
- 
215
-.you {
216
-  border-color: transparent #fff transparent transparent;
217
-}
218
- 
219
-._span {
220
-  border-color: #fff transparent transparent;
221
-  top: -17px;
222
-}
223
- 
224
-.is_ai_btn {
225
-  border-radius: 0 0 7px 7px;
226
-  border-top: 1px solid #d0d0d0;
227
-  background: white;
228
-  position: relative;
229
-  bottom: 0;
230
-  left: 0;
231
-  width: 100%;
232
-  height: 80rpx;
233
-  line-height: 80rpx;
234
-  display: flex;
235
-  flex-direction: row;
236
-  text-align: center;
237
-}
238
- 
239
-.is_ai_btn view {
240
-  width: 50%;
241
-}
242
- 
243
-.is_ai_btn image {
244
-  width: 32rpx;
245
-  position: relative;
246
-  top: 4rpx;
247
-  height: 32rpx;
248
-}
249
- 
250
-.is_ai_btn .two {
251
-  border-left: 1px solid #d0d0d0;
252
-}
253
- 
254
-.yes_problem_log {
255
-  border-top: 1px solid #d0d0d0;
256
-  height: 80rpx;
257
-  text-align: center;
258
-  line-height: 80rpx;
259
-}
260
- 
261
-.voice_icon {
262
-  width: 60rpx;
263
-  height: 60rpx;
264
-  margin: 0 auto;
265
-  padding: 10rpx 10rpx 10rpx 10rpx;
266
-}
267
- 
268
-.add_icon {
269
-  width: 70rpx;
270
-  height: 70rpx;
271
-  margin: 0 auto;
272
-  padding: 20rpx 10rpx 10rpx 15rpx;
273
-}
274
- 
275
-.voice_ing {
276
-  width: 90%;
277
-  height: 75rpx;
278
-  line-height: 85rpx;
279
-  text-align: center;
280
-  border-radius: 15rpx;
281
-  border: 1px solid #d0d0d0;
282
-}
283
- 
284
-.zezhao {
285
-  height: 100%;
286
-  position: absolute;
287
-  top: 0;
288
-  left: 0;
289
-  z-index: 2;
290
-  width: 100%;
291
-  background: rgba(0, 0, 0, 0.5);
292
-}
293
- 
294
-.in_voice_icon {
295
-  z-index: 3;
296
-  left: 0;
297
-  bottom: 0;
298
-  width: 100%;
299
-  position: absolute;
300
-  height: 500rpx;
301
-  background: #f8f8f8;
302
-}
303
- 
304
-.in_voice_icon .item {
305
-  position: relative;
306
-  margin-top: 50rpx;
307
-  margin-left: 50rpx;
308
-  text-align: center;
309
-  width: 140rpx;
310
-}
311
- 
312
-.in_voice_icon .img {
313
-  width: 80rpx;
314
-  height: 80rpx;
315
-  border-radius: 15rpx;
316
-}
317
- 
318
-.in_voice_icon .text {
319
-  font-size: 32rpx;
320
-  margin-top: 20rpx;
321
-}
322
- 
323
-.sendmessage {
324
-  width: 100%;
325
-  z-index: 2;
326
-  display: flex;
327
-  position: fixed;
328
-  bottom: 0px;
329
-  background-color: #f8f8f8;
330
-  flex-direction: row;
331
-  height: 100rpx;
332
-}
333
- 
334
-.sendmessage input {
335
-  width: 78%;
336
-  height: 80rpx;
337
-  line-height: 80rpx;
338
-  font-size: 28rpx;
339
-  margin-top: 10rpx;
340
-  margin-left: 20rpx;
341
-  border-bottom: 1px solid #d0d0d0;
342
-  padding-left: 20rpx;
343
-}
344
- 
345
-.sendmessage button {
346
-  border: 1px solid white;
347
-  width: 18%;
348
-  height: 80rpx;
349
-  background: #0c0;
350
-  color: white;
351
-  line-height: 80rpx;
352
-  margin-top: 10rpx;
353
-  font-size: 28rpx;
354
-}
355
- 
356
-.hei {
357
-  height: 20rpx;
358
-}
359
- 
360
-.history {
361
-  height: 88%;
362
-  display: flex;
363
-  font-size: 14px;
364
-  line-height: 50rpx;
365
-  position: relative;
366
-  top: 20rpx;
367
-}
368
- 
369
-.icno_kf {
370
-  position: fixed;
371
-  bottom: 160rpx;
372
-  margin: 0 auto;
373
-  text-align: center;
374
-  left: 50%;
375
-  margin-left: -40rpx;
376
-  width: 100rpx;
377
-  height: 100rpx;
378
-  border-radius: 50%;
1
+.mine {
2
+  padding: 48px 32px;
3
+  min-height: 100vh;
4
+  background-color: #041129;
5
+
6
+  .table {
7
+    display: flex;
8
+    .table-info {
9
+      font-family: PingFangSC-Regular;
10
+      font-size: 32px;
11
+      color: rgba(255, 255, 255, .75);
12
+      letter-spacing: 0;
13
+      height: 60px;
14
+      line-height: 60px;
15
+      padding: 0 10px;
16
+      margin-right: 20px;
17
+    }
18
+  }
19
+
20
+  .image-list {
21
+    margin-top: 50px;
22
+    display: flex;
23
+    justify-content: space-between;
24
+
25
+    .list-left {
26
+      width: 330px;
27
+    }
28
+
29
+    .list-right {
30
+      width: 330px;
31
+    }
32
+
33
+    .image-info {
34
+      margin-top: 20px;
35
+      border-radius: 8px;
36
+      border: 2px solid rgba(15, 132, 236, 1);
37
+
38
+      .info-top {
39
+        width: 100%;
40
+
41
+        .info-img {
42
+          width: 100%;
43
+          min-height: 360px;
44
+          display: block;
45
+        }
46
+      }
47
+
48
+      .info-bottom {
49
+        padding: 20px 22px;
50
+
51
+        .info-name {
52
+          font-family: PingFangSC-Medium;
53
+          font-size: 28px;
54
+          color: #FFFFFF;
55
+        }
56
+
57
+        .info-tips {
58
+          margin-top: 8px;
59
+          display: flex;
60
+          justify-content: space-between;
61
+          align-items: center;
62
+          font-family: PingFangSC-Regular;
63
+          font-size: 20px;
64
+          color: rgba(255, 255, 255, .75);
65
+
66
+          .info-tips-left {
67
+            display: flex;
68
+            align-items: center;
69
+          }
70
+
71
+          .info-tips-right {
72
+            display: flex;
73
+            align-items: center;
74
+          }
75
+
76
+          .info-head-img {
77
+            width: 32px;
78
+            height: 32px;
79
+          }
80
+
81
+          .info-sampling {
82
+            margin-left: 8px;
83
+          }
84
+
85
+          .info-like-img {
86
+            margin-left: 10px;
87
+            width: 28px;
88
+            height: 24px;
89
+            margin-right: 10px;
90
+          }
91
+        }
92
+      }
93
+    }
94
+  }
379 95
 }

+ 5 - 0
src/pages/communityDetail/index.config.js

@@ -0,0 +1,5 @@
1
+export default definePageConfig({
2
+  navigationBarTitleText: '作品详情',
3
+  enableShareAppMessage: true,
4
+  enableShareTimeline: true ,
5
+})

+ 482 - 0
src/pages/communityDetail/index.jsx

@@ -0,0 +1,482 @@
1
+import { Component } from 'react'
2
+import { View, Swiper, SwiperItem, Image, Textarea } from '@tarojs/components'
3
+import Taro, { getCurrentInstance } from '@tarojs/taro'
4
+import tool from '../../common/tool'
5
+import TaroCanvasDrawer from '../../component/taro-plugin-canvas';
6
+import * as api from '../../service/index'
7
+import './index.less'
8
+
9
+export default class Task extends Component {
10
+  $instance = getCurrentInstance()
11
+  state = {
12
+    author: {},
13
+    img_info: {},
14
+    task_info: {},
15
+    model_info: {},
16
+    style: {},
17
+    is_like: 0,
18
+    canvasImage: '',
19
+    qrCodeImg: '',
20
+    // 绘图配置文件
21
+    config: null,
22
+    // 绘制的图片
23
+    shareImage: null,
24
+    // TaroCanvasDrawer 组件状态
25
+    canvasStatus: false,
26
+    isFill: false,//是否画海报
27
+  }
28
+
29
+  componentWillMount () {
30
+    this.getDrawTaskStatus()
31
+    this.getWxCodeImg()
32
+  }
33
+
34
+  getWxCodeImg () {
35
+    api.getWxCodeImg({ code_from: 'bill' }).then(res => {
36
+      this.dataURLtoFile(res.data)
37
+    })
38
+  }
39
+  onShareAppMessage = (res) => {
40
+    let shareData = {
41
+      title: tool.shareTitle,
42
+      path: `/pages/index/index?c=${Taro.getStorageSync('user_id')}&s=rightTap`,
43
+      imageUrl: tool.shareImg
44
+    }
45
+    return shareData;
46
+  }
47
+  //base64转本地路径
48
+  dataURLtoFile (dataurl) {
49
+    let that = this
50
+    /// 获取到base64Data
51
+    var base64Data = dataurl;
52
+    /// 通过微信小程序自带方法将base64转为二进制去除特殊符号,再转回base64
53
+    base64Data = wx.arrayBufferToBase64(wx.base64ToArrayBuffer(base64Data));
54
+    /// 拼接请求头,data格式可以为image/png或者image/jpeg等,看需求
55
+    const base64ImgUrl = "data:image/png;base64," + base64Data;
56
+
57
+    const base64ImgData = base64ImgUrl.replace(/^data:image\/\w+;base64,/, '');
58
+    const buffer = new ArrayBuffer(base64ImgData.length);
59
+    const view = new Uint8Array(buffer);
60
+    for (let i = 0; i < base64ImgData.length; i++) {
61
+      view[i] = base64ImgData.charCodeAt(i);
62
+    }
63
+    const fileStream = wx.base64ToArrayBuffer(base64ImgData);
64
+    const filePath = wx.env.USER_DATA_PATH + '/test.png';
65
+    wx.getFileSystemManager().writeFile({
66
+      filePath: filePath,
67
+      data: fileStream,
68
+      encoding: 'binary',
69
+      success: function (res) {
70
+        console.log('writeFile success:', res, filePath);
71
+        that.setState({
72
+          qrCodeImg: filePath
73
+        }, () => {
74
+        })
75
+      },
76
+      fail: function (res) {
77
+        console.log('保存失败')
78
+      }
79
+    })
80
+    /// 刷新数据
81
+    return base64ImgUrl;
82
+  }
83
+  // 调用绘画 => canvasStatus 置为true、同时设置config
84
+  canvasDrawFunc () {
85
+    let sizeList = this.state.task_info.img_size.split(":")
86
+    console.log(sizeList, 375 * sizeList[1] / sizeList[0]);
87
+    let rssConfig = {
88
+      width: 345,
89
+      height: 314 * sizeList[1] / sizeList[0] + 69 + 112,
90
+      backgroundColor: 'rgba(255,255,255,0.1)',
91
+      debug: false,
92
+      pixelRatio: 3,
93
+      blocks: [
94
+        {
95
+          x: 0,
96
+          y: 0,
97
+          width: 345,
98
+          height: 314 * sizeList[1] / sizeList[0] + 69 + 112,
99
+          paddingLeft: 0,
100
+          paddingRight: 0,
101
+          borderWidth: 0,
102
+          // borderColor: '#ccc',
103
+          backgroundColor: '#FFFFFF',
104
+          borderRadius: 0,
105
+          zIndex: 1,
106
+        },
107
+      ],
108
+
109
+      images: [
110
+        {
111
+          url: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679561342726.png',
112
+          width: 154,
113
+          height: 21,
114
+          x: 16,
115
+          y: 19,
116
+          borderRadius: 12,
117
+          zIndex: 8,
118
+        },
119
+        {
120
+          url: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679561346368.png',
121
+          width: 65,
122
+          height: 4,
123
+          x: 261,
124
+          y: 28,
125
+          borderRadius: 12,
126
+          zIndex: 8,
127
+        },
128
+        {
129
+          url: this.state.img_info.img,
130
+          width: 314,
131
+          height: 314 * sizeList[1] / sizeList[0],
132
+          x: 16,
133
+          y: 69,
134
+          borderRadius: 12,
135
+          zIndex: 11,
136
+        },
137
+        {
138
+          url: this.state.qrCodeImg,
139
+          width: 72,
140
+          height: 72,
141
+          x: 258,
142
+          y: 314 * sizeList[1] / sizeList[0] + 69 + 20,
143
+          borderRadius: 12,
144
+          zIndex: 12,
145
+        },
146
+        {
147
+          url: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679562152791.png',
148
+          width: 143,
149
+          height: 38,
150
+          x: 91,
151
+          y: 314 * sizeList[1] / sizeList[0] + 69 + 34,
152
+          borderRadius: 0,
153
+          zIndex: 12,
154
+        },
155
+      ],
156
+      // texts: [
157
+      //   {
158
+      //     x: 170,
159
+      //     y: 314 * sizeList[1] / sizeList[0] + 69 + 34,
160
+      //     text: '长按扫码',
161
+      //     fontSize: 16,
162
+      //     color: '#333333',
163
+      //     opacity: 1,
164
+      //     baseLine: 'middle',
165
+      //     lineHeight: 22,
166
+      //     textAlign: 'right',
167
+      //     zIndex: 10,
168
+      //   },
169
+      //   {
170
+      //     x: 91,
171
+      //     y: 314 * sizeList[1] / sizeList[0] + 69 + 56,
172
+      //     text: '体验AI人工智能绘画',
173
+      //     fontSize: 16,
174
+      //     color: '#333333',
175
+      //     opacity: 1,
176
+      //     baseLine: 'middle',
177
+      //     lineHeight: 22,
178
+      //     textAlign: 'right',
179
+      //     zIndex: 10,
180
+      //   },
181
+      // ],
182
+    }
183
+    console.log('回执');
184
+    this.setState({
185
+      config: rssConfig,
186
+    }, () => {
187
+      this.setState({
188
+        isFill: true
189
+      })
190
+    })
191
+    Taro.showLoading({
192
+      title: '加载中...'
193
+    })
194
+  }
195
+
196
+  // 绘制成功回调函数 (必须实现)=> 接收绘制结果、重置 TaroCanvasDrawer 状态
197
+  onCreateSuccess = (result) => {
198
+    console.log('成功', result);
199
+    const { tempFilePath, errMsg } = result;
200
+    if (errMsg === 'canvasToTempFilePath:ok') {
201
+      this.setState({
202
+        shareImage: tempFilePath,
203
+        // 重置 TaroCanvasDrawer 状态,方便下一次调用
204
+        isFill: false,
205
+        config: {}
206
+      }, () => {
207
+        Taro.hideLoading();
208
+        wx.showShareImageMenu({
209
+          path: tempFilePath
210
+        })
211
+        //画图成功之后打开分享
212
+        // wx.downloadFile({
213
+        //   url: this.state.shareImage,
214
+        //   success: (res) => {
215
+        //     wx.showShareImageMenu({
216
+        //       path: res.tempFilePath
217
+        //     })
218
+        //   }
219
+        // })
220
+      })
221
+    } else {
222
+      // 重置 TaroCanvasDrawer 状态,方便下一次调用
223
+      this.setState({
224
+        isFill: false,
225
+        config: {}
226
+      })
227
+      Taro.showToast({ icon: 'none', title: errMsg || '出现错误' });
228
+      console.log(errMsg);
229
+    }
230
+    // 预览
231
+    // Taro.previewImage({
232
+    //   current: tempFilePath,
233
+    //   urls: [tempFilePath]
234
+    // })
235
+  }
236
+
237
+  // 绘制失败回调函数 (必须实现)=> 接收绘制错误信息、重置 TaroCanvasDrawer 状态
238
+  onCreateFail = (error) => {
239
+    console.log('失败');
240
+    Taro.hideLoading();
241
+    // 重置 TaroCanvasDrawer 状态,方便下一次调用
242
+    this.setState({
243
+      isFill: false,
244
+      config: {}
245
+    })
246
+    console.log(error);
247
+  }
248
+
249
+  // 保存图片至本地
250
+  saveToAlbum = () => {
251
+    const res = Taro.saveImageToPhotosAlbum({
252
+      filePath: this.state.shareImage,
253
+    });
254
+    if (res.errMsg === 'saveImageToPhotosAlbum:ok') {
255
+      Taro.showToast({
256
+        title: '保存图片成功',
257
+        icon: 'success',
258
+        duration: 2000,
259
+      });
260
+    }
261
+  }
262
+  openFill () {
263
+    this.canvasDrawFunc()
264
+  }
265
+  getDrawTaskStatus () {
266
+    let routers = this.$instance.router.params
267
+    api.getImgDetail({ img_id: routers.task_id }).then(res => {
268
+      //定时器不要轻易改,避免造成服务器攻击
269
+      if (res.code == 200) {
270
+        this.setState({
271
+          author: res.data.author,
272
+          img_info: res.data.img_info,
273
+          task_info: res.data.task_info,
274
+          model_info: res.data.model_info,
275
+          style: res.data.style,
276
+          is_like: res.data.is_like
277
+        })
278
+      }
279
+    })
280
+  }
281
+  download () {
282
+    this.downImg()
283
+  }
284
+  // 鉴权操作 判断是否有保存到相册的权限
285
+  // 有就直接下载 没有就弹窗提示给权限
286
+  downImg () {
287
+    Taro.getSetting({
288
+      success: res => {
289
+        if (!res.authSetting['scope.writePhotosAlbum']) {
290
+          Taro.authorize({
291
+            scope: 'scope.writePhotosAlbum',
292
+            success: () => {
293
+              this.doSaveImg()
294
+            },
295
+            fail: () => {
296
+              this.openConfirm()
297
+            }
298
+          })
299
+        } else {
300
+          this.doSaveImg()
301
+        }
302
+      }
303
+    })
304
+  }
305
+  // 生成临时路径 保存图片到手机
306
+  doSaveImg () {
307
+    Taro.downloadFile({
308
+      url: this.state.img_info.img,
309
+      success: res => {
310
+        Taro.saveImageToPhotosAlbum({
311
+          filePath: res.tempFilePath,
312
+          success: () => {
313
+            Taro.showToast({ title: '已保存到相册', icon: 'success' })
314
+          },
315
+          fail: () => {
316
+            Taro.showToast({ title: '保存失败', icon: 'none' })
317
+          }
318
+        })
319
+      }
320
+    })
321
+  }
322
+  // 权限弹窗
323
+  openConfirm () {
324
+    Taro.showModal({
325
+      content: '检测到您没有打开小程序相册权限,是否取设置打开?',
326
+      showCancel: true,
327
+      success: res => {
328
+        if (res.confirm) {
329
+          // 打开权限
330
+          Taro.openSetting({
331
+            success: res => {
332
+              this.doSaveImg()
333
+            }
334
+          })
335
+        }
336
+      }
337
+    })
338
+  }
339
+
340
+  copyPrompt () {
341
+    Taro.setClipboardData({
342
+      data: this.state.task_info.prompt,
343
+      success: function (res) {
344
+      }
345
+    })
346
+  }
347
+
348
+  copyNegativePrompt () {
349
+    Taro.setClipboardData({
350
+      data: this.state.task_info.negative_prompt,
351
+      success: function (res) {
352
+      }
353
+    })
354
+  }
355
+
356
+  componentDidMount () { }
357
+  //页面销毁之前调用
358
+  componentWillUnmount () {
359
+  }
360
+  changeLike () {
361
+    let img_info = this.state.img_info
362
+    img_info.like_cnt = this.state.is_like == 0 ? this.state.img_info.like_cnt + 1 : this.state.img_info.like_cnt - 1
363
+    this.setState({
364
+      is_like: this.state.is_like == 0 ? 1 : 0,
365
+      img_info: img_info
366
+    })
367
+    api.userLike({ img_id: this.state.img_info.id }).then(res => {
368
+
369
+    })
370
+  }
371
+  previewImage () {
372
+    Taro.previewImage({
373
+      current: this.state.img_info.img, // 当前显示图片的http链接  
374
+      urls: [`${this.state.img_info.img}`] // 需要预览的图片http链接列表  
375
+    })
376
+  }
377
+
378
+
379
+  render () {
380
+    return (
381
+      <View className='mine'>
382
+        <View className='banner-info'>
383
+          <Image className='banner-image' mode='aspectFit' onClick={e => (this.previewImage())} src={this.state.img_info.img}></Image>
384
+        </View>
385
+        <View className='content'>
386
+          <View className='draw-title'>画家信息</View>
387
+          <View className='user-text'>
388
+            <View className='user-left'>
389
+              <Image className='user-img' src={this.state.author.head_img}></Image>
390
+              <View className='user-name'>{this.state.author.user_name}</View>
391
+            </View>
392
+            <View className='like' onClick={e => { this.changeLike() }}>
393
+              <Image className='like-img' src={this.state.is_like == 0 ? 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679296882735.png' : 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679296893058.png'}></Image>
394
+              <View className='like-num'>{this.state.img_info.like_cnt}</View>
395
+            </View>
396
+          </View>
397
+          <View className='draw-title'>绘画描述</View>
398
+          <View className='draw-text'>
399
+            <Textarea
400
+              value={this.state.task_info.prompt}
401
+              className='draw-taxtarea'
402
+              placeholder='| 请输入相关描述,也可以输入关键词~'
403
+              showCount
404
+              disabled
405
+              maxlength='1000'
406
+            />
407
+            <View className='copy'>
408
+              <View className='copy-button' onClick={e => (this.copyPrompt())}>
409
+                <Image className='copy-icon' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679017836200.png'></Image>
410
+                <View>复制</View>
411
+              </View>
412
+            </View>
413
+
414
+          </View>
415
+          <View className='draw-content'>
416
+            <View className='draw-info'>
417
+              <View className='info-title'>模型</View>
418
+              <View className='info-text'>{this.state.model_info.name} </View>
419
+            </View>
420
+            <View className='draw-info'>
421
+              <View className='info-title'>风格</View>
422
+              <View className='info-text'>{this.state.style.name} </View>
423
+            </View>
424
+            <View className='draw-info'>
425
+              <View className='info-title'>图片尺寸</View>
426
+              <View className='info-text'>{this.state.task_info.img_size} </View>
427
+            </View>
428
+            {/* <View className='draw-info'>
429
+              <View className='info-title'>图片质量</View>
430
+              <View className='info-text'>{} </View>
431
+            </View> */}
432
+          </View>
433
+          <View className='draw-title'>绘画不要的元素</View>
434
+          <View className='draw-text'>
435
+            <Textarea
436
+              value={this.state.task_info.negative_prompt}
437
+              className='draw-taxtarea'
438
+              placeholder='| 请输入相关描述,也可以输入关键词~'
439
+              showCount
440
+              maxlength='1000'
441
+              disabled
442
+            />
443
+            <View className='copy'>
444
+              <View className='copy-button' onClick={e => (this.copyNegativePrompt())}>
445
+                <Image className='copy-icon' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679017836200.png'></Image>
446
+                <View>复制</View>
447
+              </View>
448
+            </View>
449
+          </View>
450
+        </View>
451
+        <View className='func'>
452
+          <View className='func-list'>
453
+            {/* <View className='func-info'>
454
+              <Image className='func-image' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1678952380367.png'></Image>
455
+              <View>发布</View>
456
+            </View> */}
457
+            {
458
+              this.state.qrCodeImg.length > 0 &&
459
+              <View className='func-info' onClick={e => (this.openFill())}>
460
+                <Image className='func-image' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1678952396973.png'></Image>
461
+                <View>分享</View>
462
+              </View>
463
+            }
464
+            <View className='func-info' onClick={e => (this.download())}>
465
+              <Image className='func-image' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1678952411029.png'></Image>
466
+              <View>下载</View>
467
+            </View>
468
+          </View>
469
+        </View>
470
+        {
471
+          this.state.isFill &&
472
+          <TaroCanvasDrawer
473
+            config={this.state.config} // 绘制配置
474
+            onCreateSuccess={e => (this.onCreateSuccess(e))} // 绘制成功回调
475
+            onCreateFail={e => (this.onCreateFail(e))} // 绘制失败回调
476
+          />
477
+        }
478
+      </View>
479
+
480
+    )
481
+  }
482
+}

+ 153 - 0
src/pages/communityDetail/index.less

@@ -0,0 +1,153 @@
1
+.mine {
2
+  min-height: 100vh;
3
+  background-color: #041129;
4
+  padding-bottom: 120px;
5
+
6
+
7
+  .banner-info {
8
+    width: 100%;
9
+    height: 750px;
10
+
11
+    .banner-image {
12
+      width: 100%;
13
+      height: 100%;
14
+    }
15
+  }
16
+
17
+  .content {
18
+    padding: 0 30px;
19
+
20
+    .user-text {
21
+      display: flex;
22
+      justify-content: space-between;
23
+      font-family: PingFangSC-Regular;
24
+      font-size: 28px;
25
+      color: rgba(255, 255, 255, .75);
26
+      font-family: PingFangSC-Regular;
27
+      font-size: 28px;
28
+      color: rgba(255,255,255,.75);
29
+
30
+      .user-left {
31
+        display: flex;
32
+        align-items: center;
33
+        .user-img {
34
+          width: 56px;
35
+          height: 56px;
36
+          display: block;
37
+          margin-right: 20px;
38
+        }
39
+
40
+      }
41
+
42
+      .like {
43
+        display: flex;
44
+        align-items: center;
45
+        .like-img {
46
+          width: 36px;
47
+          height: 36px;
48
+          margin-right: 6px;
49
+        }
50
+      }
51
+    }
52
+
53
+    .draw-title {
54
+      margin-top: 48px;
55
+      font-family: PingFangSC-Regular;
56
+      font-size: 32px;
57
+      color: #FFFFFF;
58
+    }
59
+
60
+    .draw-text {
61
+      margin-top: 20px;
62
+
63
+      .draw-taxtarea {
64
+        width: 642px;
65
+        background-color: rgba(255, 255, 255, .05);
66
+        color: rgba(255, 255, 255, .5);
67
+        min-height: 240px;
68
+        padding: 24px;
69
+      }
70
+
71
+      .copy {
72
+        margin-top: 20px;
73
+        display: flex;
74
+        justify-content: flex-end;
75
+
76
+        .copy-button {
77
+          display: flex;
78
+          align-items: center;
79
+          border: 2px solid #0F84EC;
80
+          color: #0F84EC;
81
+          font-size: 24px;
82
+          padding: 5px 20px;
83
+          border-radius: 30px;
84
+
85
+          .copy-icon {
86
+            width: 24px;
87
+            height: 24px;
88
+            margin-right: 10px;
89
+          }
90
+        }
91
+      }
92
+    }
93
+
94
+    .draw-content {
95
+      margin-top: 48px;
96
+
97
+      .draw-info {
98
+        margin-top: 1px;
99
+        background: #0F1A2F;
100
+
101
+        padding: 0 30px;
102
+        display: flex;
103
+        justify-content: space-between;
104
+        align-items: center;
105
+        height: 112px;
106
+        font-family: PingFangSC-Regular;
107
+        font-size: 32px;
108
+        color: rgba(255, 255, 255, .75);
109
+      }
110
+
111
+      .draw-info:first-child {
112
+        border-radius: 16px 16px 0 0;
113
+      }
114
+
115
+      .draw-info:last-child {
116
+        border-radius: 0 0 16px 16px;
117
+      }
118
+    }
119
+
120
+  }
121
+
122
+  .func {
123
+    width: 100%;
124
+    margin-top: 76px;
125
+
126
+    .func-list {
127
+      padding: 0 30px;
128
+      display: flex;
129
+      justify-content: space-evenly;
130
+    }
131
+
132
+    .func-info {
133
+      display: flex;
134
+      justify-content: center;
135
+      align-items: center;
136
+      width: 218px;
137
+      height: 80px;
138
+      border-radius: 8px;
139
+      border: 2px solid rgba(16, 133, 237, 1);
140
+      font-family: PingFangSC-Regular;
141
+      font-size: 32px;
142
+      color: #38ADF4;
143
+      letter-spacing: 0;
144
+      text-align: center;
145
+
146
+      .func-image {
147
+        margin-right: 22px;
148
+        width: 48px;
149
+        height: 48px;
150
+      }
151
+    }
152
+  }
153
+}

+ 3 - 1
src/pages/darwDetail/index.config.js

@@ -1,3 +1,5 @@
1 1
 export default definePageConfig({
2
-  navigationBarTitleText: '作品详情'
2
+  navigationBarTitleText: '作品详情',
3
+  enableShareAppMessage: true,
4
+  enableShareTimeline: true ,
3 5
 })

+ 342 - 27
src/pages/darwDetail/index.jsx

@@ -1,6 +1,8 @@
1 1
 import { Component } from 'react'
2
-import { View, Swiper, SwiperItem, Image, Textarea } from '@tarojs/components'
3
-import Taro, { getCurrentInstance } from '@tarojs/taro'
2
+import { View, Swiper, SwiperItem, Image, Textarea, Canvas, Button } from '@tarojs/components'
3
+import Taro, { getCurrentInstance, CanvasContext } from '@tarojs/taro'
4
+import tool from '../../common/tool'
5
+import TaroCanvasDrawer from '../../component/taro-plugin-canvas';
4 6
 import * as api from '../../service/index'
5 7
 import './index.less'
6 8
 
@@ -12,12 +14,79 @@ export default class Task extends Component {
12 14
     draw_infos: [],
13 15
     que_cnt: 0,
14 16
     default_img: '',
15
-    interval: null
17
+    interval: null,
18
+    current: 0,
19
+    model_info: {},
20
+    style_info: {},
21
+    canvasImage: '',
22
+    qrCodeImg: '',
23
+    // 绘图配置文件
24
+    config: null,
25
+    // 绘制的图片
26
+    shareImage: null,
27
+    // TaroCanvasDrawer 组件状态
28
+    canvasStatus: false,
29
+    isFill: false,//是否画海报
30
+  }
31
+
32
+  componentDidMount () {
16 33
 
17 34
   }
18 35
 
19 36
   componentWillMount () {
37
+    this.getWxCodeImg()
20 38
     this.getDrawTaskStatus()
39
+    // this.getWxCodeImg ()
40
+  }
41
+  getWxCodeImg () {
42
+    api.getWxCodeImg({ code_from: 'bill' }).then(res => {
43
+      this.dataURLtoFile(res.data)
44
+    })
45
+  }
46
+  onShareAppMessage = (res) => {
47
+    let shareData = {
48
+      title: tool.shareTitle,
49
+      path: `/pages/index/index?c=${Taro.getStorageSync('user_id')}&s=rightTap`,
50
+      imageUrl: tool.shareImg
51
+    }
52
+    return shareData;
53
+  }
54
+
55
+  //base64转本地路径
56
+  dataURLtoFile (dataurl) {
57
+    let that = this
58
+    /// 获取到base64Data
59
+    var base64Data = dataurl;
60
+    /// 通过微信小程序自带方法将base64转为二进制去除特殊符号,再转回base64
61
+    base64Data = wx.arrayBufferToBase64(wx.base64ToArrayBuffer(base64Data));
62
+    /// 拼接请求头,data格式可以为image/png或者image/jpeg等,看需求
63
+    const base64ImgUrl = "data:image/png;base64," + base64Data;
64
+
65
+    const base64ImgData = base64ImgUrl.replace(/^data:image\/\w+;base64,/, '');
66
+    const buffer = new ArrayBuffer(base64ImgData.length);
67
+    const view = new Uint8Array(buffer);
68
+    for (let i = 0; i < base64ImgData.length; i++) {
69
+      view[i] = base64ImgData.charCodeAt(i);
70
+    }
71
+    const fileStream = wx.base64ToArrayBuffer(base64ImgData);
72
+    const filePath = wx.env.USER_DATA_PATH + '/test.png';
73
+    wx.getFileSystemManager().writeFile({
74
+      filePath: filePath,
75
+      data: fileStream,
76
+      encoding: 'binary',
77
+      success: function (res) {
78
+        console.log('writeFile success:', res, filePath);
79
+        that.setState({
80
+          qrCodeImg: filePath
81
+        }, () => {
82
+        })
83
+      },
84
+      fail: function (res) {
85
+        console.log('保存失败')
86
+      }
87
+    })
88
+    /// 刷新数据
89
+    return base64ImgUrl;
21 90
   }
22 91
   getDrawTaskStatus () {
23 92
     let routers = this.$instance.router.params
@@ -43,11 +112,22 @@ export default class Task extends Component {
43 112
         } else {
44 113
           clearInterval(this.state.interval)
45 114
         }
115
+        let _current = 0
116
+        if (res.data.draw_infos.length > 1 && routers.img_id) {
117
+          res.data.draw_infos.forEach((item, index) => {
118
+            if (routers.img_id == item.id) {
119
+              _current = index
120
+            }
121
+          })
122
+        }
46 123
         this.setState({
47 124
           draw_status: res.data.draw_status,
48 125
           draw_data: res.data.draw_data,
49 126
           que_cnt: res.data.que_cnt,
50
-          draw_infos: draw_infos
127
+          draw_infos: draw_infos,
128
+          current: _current,
129
+          model_info: res.data.model_info,
130
+          style_info: res.data.style_info
51 131
         })
52 132
       }
53 133
     })
@@ -122,6 +202,21 @@ export default class Task extends Component {
122 202
     })
123 203
   }
124 204
 
205
+  copyPrompt () {
206
+    Taro.setClipboardData({
207
+      data: this.state.draw_data.prompt,
208
+      success: function (res) {
209
+      }
210
+    })
211
+  }
212
+
213
+  copyNegativePrompt () {
214
+    Taro.setClipboardData({
215
+      data: this.state.draw_data.negative_prompt,
216
+      success: function (res) {
217
+      }
218
+    })
219
+  }
125 220
 
126 221
   componentDidMount () { }
127 222
   //页面销毁之前调用
@@ -129,6 +224,202 @@ export default class Task extends Component {
129 224
     //避免服务器攻击
130 225
     clearInterval(this.state.interval)
131 226
   }
227
+  previewImage (item, index) {
228
+    Taro.previewImage({
229
+      current: item.img, // 当前显示图片的http链接  
230
+      urls: [`${item.img}`] // 需要预览的图片http链接列表  
231
+    })
232
+  }
233
+  // 调用绘画 => canvasStatus 置为true、同时设置config
234
+  canvasDrawFunc () {
235
+    let sizeList = this.state.draw_data.img_size.split(":")
236
+    console.log(sizeList, 375 * sizeList[1] / sizeList[0]);
237
+    let rssConfig = {
238
+      width: 345,
239
+      height: 314 * sizeList[1] / sizeList[0] + 69 + 112,
240
+      backgroundColor: 'rgba(255,255,255,0.1)',
241
+      debug: false,
242
+      pixelRatio: 3,
243
+      blocks: [
244
+        {
245
+          x: 0,
246
+          y: 0,
247
+          width: 345,
248
+          height: 314 * sizeList[1] / sizeList[0] + 69 + 112,
249
+          paddingLeft: 0,
250
+          paddingRight: 0,
251
+          borderWidth: 0,
252
+          // borderColor: '#ccc',
253
+          backgroundColor: '#FFFFFF',
254
+          borderRadius: 0,
255
+          zIndex: 1,
256
+        },
257
+      ],
258
+
259
+      images: [
260
+        {
261
+          url: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679561342726.png',
262
+          width: 154,
263
+          height: 21,
264
+          x: 16,
265
+          y: 19,
266
+          borderRadius: 12,
267
+          zIndex: 8,
268
+        },
269
+        {
270
+          url: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679561346368.png',
271
+          width: 65,
272
+          height: 4,
273
+          x: 261,
274
+          y: 28,
275
+          borderRadius: 12,
276
+          zIndex: 8,
277
+        },
278
+        {
279
+          url: this.state.draw_infos[this.state.current].img,
280
+          width: 314,
281
+          height: 314 * sizeList[1] / sizeList[0],
282
+          x: 16,
283
+          y: 69,
284
+          borderRadius: 12,
285
+          zIndex: 11,
286
+        },
287
+        {
288
+          url: this.state.qrCodeImg,
289
+          width: 72,
290
+          height: 72,
291
+          x: 258,
292
+          y: 314 * sizeList[1] / sizeList[0] + 69 + 20,
293
+          borderRadius: 12,
294
+          zIndex: 12,
295
+        },
296
+        {
297
+          url: 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679562152791.png',
298
+          width: 143,
299
+          height: 38,
300
+          x: 91,
301
+          y: 314 * sizeList[1] / sizeList[0] + 69 + 34,
302
+          borderRadius: 0,
303
+          zIndex: 12,
304
+        },
305
+      ],
306
+      // texts: [
307
+      //   {
308
+      //     x: 170,
309
+      //     y: 314 * sizeList[1] / sizeList[0] + 69 + 34,
310
+      //     text: '长按扫码',
311
+      //     fontSize: 16,
312
+      //     color: '#333333',
313
+      //     opacity: 1,
314
+      //     baseLine: 'middle',
315
+      //     lineHeight: 22,
316
+      //     textAlign: 'right',
317
+      //     zIndex: 10,
318
+      //   },
319
+      //   {
320
+      //     x: 91,
321
+      //     y: 314 * sizeList[1] / sizeList[0] + 69 + 56,
322
+      //     text: '体验AI人工智能绘画',
323
+      //     fontSize: 16,
324
+      //     color: '#333333',
325
+      //     opacity: 1,
326
+      //     baseLine: 'middle',
327
+      //     lineHeight: 22,
328
+      //     textAlign: 'right',
329
+      //     zIndex: 10,
330
+      //   },
331
+      // ],
332
+    }
333
+    console.log('回执');
334
+    this.setState({
335
+      config: rssConfig,
336
+    }, () => {
337
+      this.setState({
338
+        isFill: true
339
+      })
340
+    })
341
+    Taro.showLoading({
342
+      title: '加载中...'
343
+    })
344
+  }
345
+
346
+  // 绘制成功回调函数 (必须实现)=> 接收绘制结果、重置 TaroCanvasDrawer 状态
347
+  onCreateSuccess = (result) => {
348
+    console.log('成功', result);
349
+    const { tempFilePath, errMsg } = result;
350
+    Taro.hideLoading();
351
+
352
+    if (errMsg === 'canvasToTempFilePath:ok') {
353
+      this.setState({
354
+        shareImage: tempFilePath,
355
+        // 重置 TaroCanvasDrawer 状态,方便下一次调用
356
+        isFill: false,
357
+        config: {}
358
+      }, () => {
359
+        wx.showShareImageMenu({
360
+          path: tempFilePath
361
+        })
362
+      })
363
+       //画图成功之后打开分享
364
+      //  wx.downloadFile({
365
+      //   url: tempFilePath,
366
+      //   success: (res) => {
367
+      //     console.log('打开分享');
368
+      //     wx.showShareImageMenu({
369
+      //       path: res.tempFilePath
370
+      //     })
371
+      //   }
372
+      // })
373
+    } else {
374
+      // 重置 TaroCanvasDrawer 状态,方便下一次调用
375
+      this.setState({
376
+        isFill: false,
377
+        config: {}
378
+      })
379
+      Taro.showToast({ icon: 'none', title: errMsg || '出现错误' });
380
+      console.log(errMsg);
381
+    }
382
+    // 预览
383
+    // Taro.previewImage({
384
+    //   current: tempFilePath,
385
+    //   urls: [tempFilePath]
386
+    // })
387
+  }
388
+
389
+  // 绘制失败回调函数 (必须实现)=> 接收绘制错误信息、重置 TaroCanvasDrawer 状态
390
+  onCreateFail = (error) => {
391
+    console.log('失败');
392
+    Taro.hideLoading();
393
+    // 重置 TaroCanvasDrawer 状态,方便下一次调用
394
+    this.setState({
395
+      isFill: false,
396
+      config: {}
397
+    })
398
+    console.log(error);
399
+  }
400
+
401
+  // 保存图片至本地
402
+  saveToAlbum = () => {
403
+    const res = Taro.saveImageToPhotosAlbum({
404
+      filePath: this.state.shareImage,
405
+    });
406
+    if (res.errMsg === 'saveImageToPhotosAlbum:ok') {
407
+      Taro.showToast({
408
+        title: '保存图片成功',
409
+        icon: 'success',
410
+        duration: 2000,
411
+      });
412
+    }
413
+  }
414
+  openFill () {
415
+    this.canvasDrawFunc()
416
+  }
417
+  changeCurrent(e){
418
+    this.setState({
419
+      current:e.detail.current
420
+    })
421
+    console.log(e,'eeee');
422
+  }
132 423
 
133 424
 
134 425
   render () {
@@ -139,14 +430,16 @@ export default class Task extends Component {
139 430
           indicatorColor='#121D34'
140 431
           indicatorActiveColor='#0F84EC'
141 432
           circular
433
+          current={this.state.current}
142 434
           adjustHeight='first'
435
+          onChange={e=>(this.changeCurrent(e))}
143 436
           indicatorDots
144
-          autoplay>
437
+          >
145 438
           {
146 439
             this.state.draw_infos.map((item, index) => (
147 440
               <SwiperItem key={index}>
148 441
                 <View className='banner-info'>
149
-                  <Image className='banner-image' mode='aspectFit' src={item.img}></Image>
442
+                  <Image className='banner-image' mode='aspectFit' src={item.img} onClick={e => (this.previewImage(item, index))}></Image>
150 443
                 </View>
151 444
               </SwiperItem>
152 445
             ))
@@ -154,15 +447,9 @@ export default class Task extends Component {
154 447
           {
155 448
             this.state.draw_status != 2 &&
156 449
             <View className='banner-tips'>
157
-              预计等待{this.state.que_cnt + 1}分钟...
450
+              预计等待{Math.floor((this.state.que_cnt - 1)*0.2+1)}分钟...
158 451
             </View>
159 452
           }
160
-          {/* <SwiperItem>
161
-            <View className='demo-text-2'><Image ></Image></View>
162
-          </SwiperItem>
163
-          <SwiperItem>
164
-            <View className='demo-text-3'><Image ></Image></View>
165
-          </SwiperItem> */}
166 453
         </Swiper>
167 454
         <View className='content'>
168 455
           <View className='draw-title'>绘画描述</View>
@@ -171,19 +458,26 @@ export default class Task extends Component {
171 458
               value={this.state.draw_data.prompt}
172 459
               className='draw-taxtarea'
173 460
               placeholder='| 请输入相关描述,也可以输入关键词~'
461
+              maxlength='1000'
174 462
               showCount
175 463
               disabled
176 464
             />
177
-            
465
+            <View className='copy'>
466
+              <View className='copy-button' onClick={e => (this.copyPrompt())}>
467
+                <Image className='copy-icon' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679017836200.png'></Image>
468
+                <View>复制</View>
469
+              </View>
470
+            </View>
471
+
178 472
           </View>
179 473
           <View className='draw-content'>
180 474
             <View className='draw-info'>
181 475
               <View className='info-title'>模型</View>
182
-              <View className='info-text'>{this.state.draw_data.model_name} </View>
476
+              <View className='info-text'>{this.state.model_info.name} </View>
183 477
             </View>
184 478
             <View className='draw-info'>
185 479
               <View className='info-title'>风格</View>
186
-              <View className='info-text'>{ } </View>
480
+              <View className='info-text'>{this.state.style_info.name} </View>
187 481
             </View>
188 482
             <View className='draw-info'>
189 483
               <View className='info-title'>图片尺寸</View>
@@ -202,25 +496,46 @@ export default class Task extends Component {
202 496
               placeholder='| 请输入相关描述,也可以输入关键词~'
203 497
               showCount
204 498
               disabled
499
+              maxlength='1000'
205 500
             />
501
+            <View className='copy'>
502
+              <View className='copy-button' onClick={e => (this.copyNegativePrompt())}>
503
+                <Image className='copy-icon' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679017836200.png'></Image>
504
+                <View>复制</View>
505
+              </View>
506
+            </View>
206 507
           </View>
207 508
         </View>
208
-        <View className='func'>
209
-          <View className='func-list'>
210
-            {/* <View className='func-info'>
509
+        {
510
+          this.state.draw_status == 2 &&
511
+          <View className='func'>
512
+            <View className='func-list'>
513
+              {/* <View className='func-info'>
211 514
               <Image className='func-image' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1678952380367.png'></Image>
212 515
               <View>发布</View>
213 516
             </View> */}
214
-            <View className='func-info'>
215
-              <Image className='func-image' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1678952396973.png'></Image>
216
-              <View>分享</View>
217
-            </View>
218
-            <View className='func-info' onClick={e => (this.download())}>
219
-              <Image className='func-image' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1678952411029.png'></Image>
220
-              <View>下载</View>
517
+              {
518
+                this.state.qrCodeImg.length > 0 &&
519
+                <View className='func-info' onClick={e => (this.openFill())}>
520
+                  <Image className='func-image' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1678952396973.png'></Image>
521
+                  <View>分享</View>
522
+                </View>
523
+              }
524
+              <View className='func-info' onClick={e => (this.download())}>
525
+                <Image className='func-image' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1678952411029.png'></Image>
526
+                <View>下载</View>
527
+              </View>
221 528
             </View>
222 529
           </View>
223
-        </View>
530
+        }
531
+        {
532
+          this.state.isFill &&
533
+          <TaroCanvasDrawer
534
+            config={this.state.config} // 绘制配置
535
+            onCreateSuccess={e => (this.onCreateSuccess(e))} // 绘制成功回调
536
+            onCreateFail={e => (this.onCreateFail(e))} // 绘制失败回调
537
+          />
538
+        }
224 539
       </View>
225 540
     )
226 541
   }

+ 94 - 1
src/pages/darwDetail/index.less

@@ -23,7 +23,7 @@
23 23
 
24 24
       .banner-image {
25 25
         width: 100%;
26
-        height: 100%;
26
+        min-height: 800px;
27 27
       }
28 28
     }
29 29
   }
@@ -48,6 +48,28 @@
48 48
         min-height: 240px;
49 49
         padding: 24px;
50 50
       }
51
+
52
+      .copy {
53
+        margin-top: 20px;
54
+        display: flex;
55
+        justify-content: flex-end;
56
+
57
+        .copy-button {
58
+          display: flex;
59
+          align-items: center;
60
+          border: 2px solid #0F84EC;
61
+          color: #0F84EC;
62
+          font-size: 24px;
63
+          padding: 5px 20px;
64
+          border-radius: 30px;
65
+
66
+          .copy-icon {
67
+            width: 24px;
68
+            height: 24px;
69
+            margin-right: 10px;
70
+          }
71
+        }
72
+      }
51 73
     }
52 74
 
53 75
     .draw-content {
@@ -109,4 +131,75 @@
109 131
       }
110 132
     }
111 133
   }
134
+
135
+  .poster {
136
+    position: relative;
137
+    width: 750rpx;
138
+    height: 1200rpx;
139
+  }
140
+
141
+  .poster-image {
142
+    width: 750rpx;
143
+    height: 1200rpx;
144
+  }
145
+
146
+  .poster-qrcode {
147
+    position: absolute;
148
+    right: 60rpx;
149
+    bottom: 80rpx;
150
+    width: 180rpx;
151
+    height: 180rpx;
152
+  }
153
+}
154
+
155
+.bill {
156
+  position: relative;
157
+  width: 100vw;
158
+  height: 100vh;
159
+  z-index: 10000;
160
+  position: fixed;
161
+  background-color: rgba(2, 2, 2, .7);
162
+  left: 0;
163
+  top: 0;
164
+  display: flex;
165
+  justify-content: center;
166
+  align-items: center;
167
+
168
+  .shareImage-cont {
169
+    width: 80%;
170
+
171
+    .shareImage {
172
+      width: 100%;
173
+      display: block;
174
+    }
175
+
176
+    .func-list {
177
+      margin-top: 20px;
178
+      padding: 0 30px;
179
+      display: flex;
180
+      justify-content: space-evenly;
181
+    }
182
+
183
+    .func-info {
184
+      display: flex;
185
+      justify-content: center;
186
+      align-items: center;
187
+      width: 218px;
188
+      height: 80px;
189
+      border-radius: 8px;
190
+      border: 2px solid rgba(16, 133, 237, 1);
191
+      font-family: PingFangSC-Regular;
192
+      font-size: 32px;
193
+      color: #38ADF4;
194
+      letter-spacing: 0;
195
+      text-align: center;
196
+
197
+      .func-image {
198
+        margin-right: 22px;
199
+        width: 48px;
200
+        height: 48px;
201
+      }
202
+    }
203
+  }
204
+
112 205
 }

+ 5 - 0
src/pages/earnPoints/index.config.js

@@ -0,0 +1,5 @@
1
+export default definePageConfig({
2
+  navigationBarTitleText: '获取点券',
3
+  enableShareAppMessage: true,
4
+  enableShareTimeline: true ,
5
+})

+ 238 - 0
src/pages/earnPoints/index.jsx

@@ -0,0 +1,238 @@
1
+import { Component } from 'react'
2
+import { View, Swiper, SwiperItem, Image, Textarea, Text, ScrollView, RichText } from '@tarojs/components'
3
+import Taro, { getCurrentInstance } from '@tarojs/taro'
4
+import tool from '../../common/tool'
5
+import * as api from '../../service/index'
6
+import './index.less'
7
+
8
+export default class Task extends Component {
9
+  $instance = getCurrentInstance()
10
+  state = {
11
+    userInfo: {},
12
+    taskList: [],
13
+    vip_list: [],//会员列表
14
+    shop_list: [],//充值列表
15
+    ext_info: {},//注意事项
16
+    isIos: false,
17
+  }
18
+
19
+  componentWillMount () {
20
+    if (tool.notAndroid()) {
21
+      this.setState({
22
+        isIos: true
23
+      })
24
+    }
25
+    this.getCoinTaskList()
26
+    this.getShopList()
27
+    this.getUserInfo()
28
+  }
29
+  onShareAppMessage = (res) => {
30
+    let shareData = {
31
+      title: tool.shareTitle,
32
+      path: `/pages/index/index?c=${Taro.getStorageSync('user_id')}&s=rightTap`,
33
+      imageUrl: tool.shareImg
34
+    }
35
+    return shareData;
36
+  }
37
+  //获取任务列表
38
+  getCoinTaskList () {
39
+    api.getCoinTaskList().then(res => {
40
+      this.setState({
41
+        taskList: res.data
42
+      })
43
+    })
44
+  }
45
+  getUserInfo () {
46
+    api.getUserInfo().then(res => {
47
+      if (res.code == 200) {
48
+        this.setState({
49
+          userInfo: res.data
50
+        })
51
+      }
52
+    })
53
+  }
54
+  getShopList () {
55
+    api.getShopList().then(res => {
56
+      if (res.code == 200) {
57
+        this.setState({
58
+          vip_list: res.data.vip_list,
59
+          shop_list: res.data.shop_list,
60
+          ext_info: res.data.ext_info,
61
+        })
62
+      }
63
+    })
64
+  }
65
+  finishTask (item, index) {
66
+    api.finishTask({ task_id: item.id }).then(res => {
67
+      if (res.code == 200) {
68
+        this.getUserInfo()
69
+        this.getCoinTaskList()
70
+      }
71
+    })
72
+  }
73
+  //充值
74
+  toOrder (item, index) {
75
+    let that = this
76
+    Taro.getSystemInfo({
77
+      success: function (res) {
78
+        Taro.showLoading({
79
+          title: '加载中...',
80
+        })
81
+        api.createOrder({ shop_id: item.id }).then(res => {
82
+          if (res.code == 200) {
83
+            Taro.hideLoading()
84
+            Taro.requestPayment({
85
+              timeStamp: res.data.timeStamp,
86
+              nonceStr: res.data.nonceStr,
87
+              package: res.data.package,
88
+              signType: res.data.signType,
89
+              paySign: res.data.paySign,
90
+              success: function (res) {
91
+                // console.log(res);
92
+                //添加2s延迟在刷新数据
93
+                setTimeout(() => {
94
+                  that.getUserInfo()
95
+                }, 2000);
96
+              },
97
+              fail: function (err) {
98
+                try {
99
+                  const res = Taro.getSystemInfoSync()
100
+                  console.log(res, 'iphone=====');
101
+                } catch (e) {
102
+                }
103
+              }
104
+            })
105
+          }
106
+        })
107
+      }
108
+    })
109
+
110
+  }
111
+  //会员充值
112
+  memberToOrder (item, index) {
113
+    if (item.has_buy == 1) return
114
+    let that = this
115
+    Taro.getSystemInfo({
116
+      success: function (res) {
117
+        Taro.showLoading({
118
+          title: '加载中...',
119
+        })
120
+        api.createOrder({ shop_id: item.id }).then(res => {
121
+          if (res.code == 200) {
122
+            Taro.hideLoading()
123
+            Taro.requestPayment({
124
+              timeStamp: res.data.timeStamp,
125
+              nonceStr: res.data.nonceStr,
126
+              package: res.data.package,
127
+              signType: res.data.signType,
128
+              paySign: res.data.paySign,
129
+              success: function (res) {
130
+                // console.log(res);
131
+                //添加2s延迟在刷新数据
132
+                setTimeout(() => {
133
+                  this.getCoinTaskList()
134
+                  this.getShopList()
135
+                  this.getUserInfo()
136
+                }, 2000);
137
+              },
138
+              fail: function (err) {
139
+                try {
140
+                  const res = Taro.getSystemInfoSync()
141
+                  console.log(res, 'iphone=====');
142
+                } catch (e) {
143
+                }
144
+              }
145
+            })
146
+          }
147
+        })
148
+      }
149
+    })
150
+
151
+  }
152
+  componentDidMount () { }
153
+  //页面销毁之前调用
154
+  componentWillUnmount () {
155
+    //避免服务器攻击
156
+  }
157
+
158
+
159
+  render () {
160
+    return (
161
+      <View className='mine'>
162
+        <View className='banner'>
163
+          <View className='banner-left'>
164
+            <View className='banner-title'>剩余积分:</View>
165
+            <View className='banner-num'>{this.state.userInfo.total_coin}</View>
166
+          </View>
167
+          <View className='banner-right'>
168
+            <Image className='banner-img' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679465544881.png'></Image>
169
+          </View>
170
+        </View>
171
+        <View className='content'>
172
+          {
173
+            this.state.taskList.map((item, index) => (
174
+              <View className='register' key={index}>
175
+                <View className='register-left'>
176
+                  <View className='register-title'><Image className='register-icon' src={item.img} ></Image> {item.title}</View>
177
+                  <View className='register-tips'>{item.sub_title}</View>
178
+                </View>
179
+                <View className='register-right' style={item.status == 0 ? '' : 'background-image: linear-gradient(-45deg, #0c1419 0%, #3b3d3e 100%);opacity: 0.5;'} onClick={e => (this.finishTask(item, index))}>{item.btn_title}</View>
180
+              </View>
181
+            ))
182
+          }
183
+          {
184
+            !this.state.isIos &&
185
+            < View >
186
+              <View className='contact-title'>
187
+                点券充值
188
+              </View>
189
+              <ScrollView
190
+                className='recharge'
191
+                scrollX
192
+              >
193
+                {
194
+                  this.state.shop_list.map((item, index) => (
195
+                    <View className='recharge-info' key={index}>
196
+                      <View className='recharge-icon'><Image className='recharge-img' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679457146188.png'> </Image></View>
197
+                      <View className='recharge-tips'>{item.sub_title}</View>
198
+                      <View className='recharge-title'>{item.title}</View>
199
+                      <View className='recharge-tag'>{item.tag}</View>
200
+                      <View className='recharge-button' onClick={e => (this.toOrder(item, index))}>充值</View>
201
+                    </View>
202
+                  ))
203
+                }
204
+              </ScrollView>
205
+              <View className='contact-title'>
206
+                会员充值
207
+              </View>
208
+              <View className='member-list'>
209
+                {
210
+                  this.state.vip_list.map((item, index) => (
211
+                    <View className='member-info' key={index}>
212
+                      <View className='member-top'>
213
+                        <RichText className='member-title' nodes={item.title}></RichText>
214
+                        <View className='member-tag'>{item.tag}</View>
215
+                      </View>
216
+                      <View className='member-bottom'>
217
+                        <View className='member-bottom-left'>
218
+                          <RichText nodes={item.sub_title}></RichText>
219
+                        </View>
220
+                        <View className='member-button' style={item.has_buy == 1 ? 'background-image: linear-gradient(-45deg, #0c1419 0%, #3b3d3e 100%);opacity: 0.5;' : ''} onClick={e => (this.memberToOrder(item, index))}>{item.has_buy == 1 ? '已开通' : '开通'}</View>
221
+                      </View>
222
+                    </View>
223
+                  ))
224
+                }
225
+              </View>
226
+            </View>
227
+          }
228
+          {
229
+            this.state.isIos &&
230
+            <View className='ios-tips'>
231
+              ios暂不支持充值
232
+            </View>
233
+          }
234
+        </View>
235
+      </View >
236
+    )
237
+  }
238
+}

+ 249 - 0
src/pages/earnPoints/index.less

@@ -0,0 +1,249 @@
1
+.mine {
2
+  min-height: 100vh;
3
+  background-color: #041129;
4
+  padding-bottom: 120px;
5
+
6
+  .banner {
7
+    display: flex;
8
+    justify-content: space-between;
9
+    align-items: center;
10
+
11
+    .banner-left {
12
+      margin-left: 60px;
13
+      .banner-title {
14
+        font-family: PingFangSC-Regular;
15
+        font-size: 28px;
16
+        color: rgba(255, 255, 255, .75);
17
+      }
18
+
19
+      .banner-num {
20
+        font-family: DINPro-Medium;
21
+        font-size: 64px;
22
+        color: #0F84EC;
23
+      }
24
+    }
25
+    .banner-right{
26
+      .banner-img{
27
+        width: 350px;
28
+        height: 270px;
29
+      }
30
+    }
31
+  }
32
+
33
+  .content {
34
+    position: relative;
35
+    z-index: 1111;
36
+    margin-top: -60px;
37
+    padding: 0 30px;
38
+
39
+    .register {
40
+      margin-bottom: 12px;
41
+      border-radius: 16px;
42
+      width: 100%;
43
+      background: #0F1A2F;
44
+      height: 112px;
45
+      display: flex;
46
+      align-items: center;
47
+
48
+      .register-left {
49
+        padding-left: 30px;
50
+        flex: 1;
51
+        display: flex;
52
+        justify-content: space-between;
53
+        align-items: center;
54
+        font-size: 28px;
55
+        color: rgba(255, 255, 255, .75);
56
+
57
+        .register-title {
58
+          display: flex;
59
+          align-items: center;
60
+
61
+          .register-icon {
62
+            width: 48px;
63
+            height: 48px;
64
+            margin-right: 20px;
65
+          }
66
+
67
+          font-family: PingFangSC-Regular;
68
+          font-size: 32px;
69
+          color: #FFFFFF;
70
+          letter-spacing: 0;
71
+        }
72
+      }
73
+
74
+      .register-right {
75
+        padding: 0 22px;
76
+        height: 64px;
77
+        line-height: 64px;
78
+        text-align: center;
79
+        margin-left: 20px;
80
+        margin-right: 20px;
81
+        font-family: PingFangSC-Regular;
82
+        font-size: 32px;
83
+        color: #FFFFFF;
84
+        background-image: linear-gradient(-45deg, #4EC3F8 0%, #0F84EC 100%);
85
+        border-radius: 8px;
86
+      }
87
+    }
88
+
89
+    .register:nth-child(1) {
90
+      border-radius: 16px 16px 0 0;
91
+    }
92
+
93
+    .contact-title {
94
+      margin-top: 48px;
95
+      font-family: PingFangSC-Medium;
96
+      font-size: 32px;
97
+      color: #FFFFFF;
98
+    }
99
+
100
+    .contact-content {
101
+      margin-top: 30px;
102
+      height: 112px;
103
+      line-height: 112px;
104
+      background: #0F1A2F;
105
+      border-radius: 16px;
106
+      font-family: PingFangSC-Regular;
107
+      font-size: 32x;
108
+      color: #FFFFFF;
109
+      display: flex;
110
+      align-items: center;
111
+
112
+      .contact-icon {
113
+        margin-right: 20px;
114
+        width: 48px;
115
+        height: 48px;
116
+      }
117
+    }
118
+
119
+    .recharge {
120
+
121
+      margin-top: 30px;
122
+      width: 100%;
123
+      white-space: nowrap;
124
+
125
+      .recharge-info {
126
+        margin-right: 18px;
127
+        display: inline-block;
128
+        padding: 50px 0 24px 0;
129
+        width: 260px;
130
+        position: relative;
131
+        background: #0F1A2F;
132
+        border-radius: 16px;
133
+
134
+        .recharge-icon {
135
+          width: 100%;
136
+          display: flex;
137
+          justify-content: center;
138
+
139
+          .recharge-img {
140
+            width: 92px;
141
+            height: 64px;
142
+            display: block;
143
+          }
144
+        }
145
+
146
+        .recharge-tips {
147
+          margin-top: 16px;
148
+          position: absolute;
149
+          top: 0;
150
+          left: 0;
151
+          padding: 0 26px;
152
+          background: #DF5E5F;
153
+          border-radius: 16px 0 16px 0;
154
+          font-family: PingFangSC-Regular;
155
+          font-size: 20px;
156
+          color: #FFFFFF;
157
+        }
158
+
159
+        .recharge-title {
160
+          margin-top: 16px;
161
+          font-family: PingFangSC-Regular;
162
+          font-size: 28px;
163
+          color: #FFFFFF;
164
+          letter-spacing: 0;
165
+          text-align: center;
166
+          letter-spacing: 0;
167
+        }
168
+
169
+        .recharge-tag {
170
+          margin-top: 4px;
171
+          font-family: PingFangSC-Medium;
172
+          font-size: 24px;
173
+          color: #DF5E5F;
174
+          letter-spacing: 0;
175
+          text-align: center;
176
+          line-height: 31px;
177
+        }
178
+
179
+        .recharge-button {
180
+          margin-top: 24px;
181
+          position: relative;
182
+          left: 50%;
183
+          transform: translateX(-50%);
184
+          width: 120px;
185
+          height: 64px;
186
+          line-height: 64px;
187
+          background-image: linear-gradient(-45deg, #4EC3F8 0%, #0F84EC 100%);
188
+          border-radius: 32px;
189
+          font-family: PingFangSC-Regular;
190
+          font-size: 32px;
191
+          color: #FFFFFF;
192
+          letter-spacing: 0;
193
+          text-align: center;
194
+        }
195
+      }
196
+    }
197
+
198
+    .member-list {
199
+      .member-info {
200
+        margin-top: 30px;
201
+        padding: 15px;
202
+        background: #0F1A2F;
203
+        border-radius: 16px;
204
+
205
+        .member-top {
206
+          display: flex;
207
+          justify-content: space-between;
208
+          font-family: PingFangSC-Medium;
209
+          font-size: 32px;
210
+
211
+          .member-title {
212
+            color: #0F84EC;
213
+          }
214
+
215
+          .member-tag {
216
+            color: #FC4F79;
217
+          }
218
+        }
219
+
220
+        .member-bottom {
221
+          margin-top: 12px;
222
+          display: flex;
223
+          justify-content: space-between;
224
+          align-items: center;
225
+          font-family: PingFangSC-Regular;
226
+          font-size: 28px;
227
+          color: #FFFFFF;
228
+          line-height: 44px;
229
+
230
+          .member-button {
231
+            width: 136px;
232
+            height: 64px;
233
+            line-height: 64px;
234
+            text-align: center;
235
+            background-image: linear-gradient(-45deg, #45B7F2 0%, #0F84EC 100%);
236
+            border-radius: 64px;
237
+          }
238
+        }
239
+      }
240
+    }
241
+  }
242
+.ios-tips{
243
+  font-family: PingFangSC-Regular;
244
+  font-size: 32rpx;
245
+  color: rgba(255, 255, 255, 0.75);
246
+  margin-top: 100px;
247
+  text-align: center;
248
+}
249
+}

+ 3 - 1
src/pages/index/index.config.js

@@ -1,3 +1,5 @@
1 1
 export default definePageConfig({
2
-  navigationBarTitleText: 'AI创作'
2
+  navigationBarTitleText: 'AI创作',
3
+  enableShareAppMessage: true,
4
+  enableShareTimeline: true ,
3 5
 })

+ 61 - 11
src/pages/index/index.jsx

@@ -1,6 +1,7 @@
1 1
 import { Component } from 'react'
2 2
 import { View, Text, Button, Image, scrollView, Input, Textarea, Slider } from '@tarojs/components'
3 3
 import Taro, { getCurrentInstance } from '@tarojs/taro'
4
+import tool from '../../common/tool'
4 5
 import * as api from '../../service/index'
5 6
 
6 7
 import './index.less'
@@ -20,6 +21,7 @@ export default class Mine extends Component {
20 21
     modelIndex: 0,//当前选择的模型
21 22
     sliderNum: 7,//色彩丰富度
22 23
     drawNum: 1,//图片数量
24
+    mass: 0,//图片质量
23 25
   }
24 26
 
25 27
   componentDidShow () {
@@ -28,6 +30,15 @@ export default class Mine extends Component {
28 30
 
29 31
   componentDidMount () { }
30 32
 
33
+  onShareAppMessage = (res) => {
34
+    let shareData = {
35
+      title: tool.shareTitle,
36
+      path: `/pages/index/index?c=${Taro.getStorageSync('user_id')}&s=rightTap`,
37
+      imageUrl: tool.shareImg
38
+    }
39
+    return shareData;
40
+  }
41
+
31 42
   getMyDraw () {
32 43
     api.getMyDraw({ page_size: 100 })
33 44
   }
@@ -54,6 +65,16 @@ export default class Mine extends Component {
54 65
       }
55 66
     })
56 67
   }
68
+  deleteDrawText(){
69
+    this.setState({
70
+      value:''
71
+    })
72
+  }
73
+  deleteNegativeValue(){
74
+    this.setState({
75
+      negativeValue:''
76
+    })
77
+  }
57 78
   onInput (e) {
58 79
     console.log(e, 'e')
59 80
     var num = e.detail.cursor;
@@ -70,7 +91,7 @@ export default class Mine extends Component {
70 91
     var num = e.detail.cursor;
71 92
     document.getElementById('negative_prompt').innerHTML = num + "/1000";
72 93
   }
73
-  onBlurNegative(e){
94
+  onBlurNegative (e) {
74 95
     this.setState({
75 96
       negativeValue: e.detail.value
76 97
     })
@@ -113,8 +134,17 @@ export default class Mine extends Component {
113 134
       loraIndex: index
114 135
     })
115 136
   }
137
+  changeMass (e) {
138
+    this.setState({
139
+      mass: e
140
+    })
141
+  }
116 142
   //生成图片
117 143
   generatePictures () {
144
+    Taro.showLoading({
145
+      title: '加载中',
146
+    })
147
+
118 148
     console.log('生成图片');
119 149
     console.log();
120 150
     setTimeout(() => {
@@ -126,23 +156,33 @@ export default class Mine extends Component {
126 156
         return
127 157
       }
128 158
       let pramas = {
129
-        model_name: this.state.models[this.state.modelIndex].model_name,
130
-        file_name: this.state.models[this.state.modelIndex].lora_infos.length > 0 ? this.state.models[this.state.modelIndex].lora_infos[this.state.loraIndex].file_name : '',
159
+        // model_name: this.state.models[this.state.modelIndex].model_name,
160
+        // file_name: this.state.models[this.state.modelIndex].lora_infos.length > 0 ? this.state.models[this.state.modelIndex].lora_infos[this.state.loraIndex].file_name : '',
161
+        model_id: this.state.models[this.state.modelIndex].id,
162
+        style_id: this.state.models[this.state.modelIndex].lora_infos.length > 0 ? this.state.models[this.state.modelIndex].lora_infos[this.state.loraIndex].id : 0,
131 163
         img_size: this.state.imgSize[this.state.sizeIndex].name,
132 164
         img_cnt: this.state.drawNum,
133 165
         cfg_scale: this.state.sliderNum,
134 166
         sampler: this.state.sampling[this.state.samplingIndex],
135 167
         prompt: this.state.value,
136
-        negative_prompt: this.state.negativeValue
168
+        negative_prompt: this.state.negativeValue,
169
+        img_type: this.state.mass
137 170
       }
138 171
       api.drawTxt2img(pramas).then(res => {
139 172
         if (res.code == 200) {
173
+          Taro.hideLoading()
140 174
           Taro.navigateTo({
141 175
             url: `/pages/darwDetail/index?task_id=${res.data.task_id}`
142 176
           })
177
+        } else {
178
+          Taro.hideLoading()
179
+          Taro.showToast({
180
+            title: res.msg,
181
+            icon: 'error',
182
+          });
143 183
         }
144 184
       })
145
-    },1000)
185
+    }, 1000)
146 186
   }
147 187
   toChat (e) {
148 188
   }
@@ -154,13 +194,13 @@ export default class Mine extends Component {
154 194
           <Image className='banner-image' src=''></Image>
155 195
         </View> */}
156 196
         <View className='draw-content'>
157
-          <View className='draw-brack'>
197
+          {/* <View className='draw-brack'>
158 198
             <View className='draw-tab'>
159 199
               <View className='tab-text' style={'background: #0F84EC;color: #FFFFFF;'}>AI绘画</View>
160 200
               <View className='tab-text'>人物头像</View>
161 201
               <View className='tab-text'>风景头像</View>
162 202
             </View>
163
-          </View>
203
+          </View> */}
164 204
           <View className='draw-title'>绘画描述</View>
165 205
           <View className='draw-text'>
166 206
             <View className='recommend'>
@@ -174,8 +214,11 @@ export default class Mine extends Component {
174 214
               showCount
175 215
               onInput={e => (this.onInput(e))}
176 216
               onBlur={e => (this.onBlur(e))}
177
-
178 217
               maxlength='1000' />
218
+            {
219
+              this.state.value.length > 0 &&
220
+              <Image className='delete-draw-text' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679637370560.png' onClick={e => (this.deleteDrawText())}></Image>
221
+            }
179 222
             <View className='textarea-num' id='textarea-num'>{this.state.value.length}/1000</View>
180 223
           </View>
181 224
           <View className='draw-title'>选择模型</View>
@@ -204,12 +247,15 @@ export default class Mine extends Component {
204 247
                 ))
205 248
             }
206 249
           </View>
250
+          {
251
+            this.state.models.length>6&&
207 252
           <View className='isOpen'>
208 253
             <View className='open-content' onClick={e => (this.changeOpen())}>
209 254
               <View className='open-title'>{!this.state.isOpen ? '展开' : '收起'}</View>
210 255
               <Image className='open-img' src={!this.state.isOpen ? 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1678935050487.png' : 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1678935114571.png'}></Image>
211 256
             </View>
212 257
           </View>
258
+          }
213 259
           {
214 260
             this.state.models[this.state.modelIndex] &&
215 261
             this.state.models[this.state.modelIndex].lora_infos.length > 0 &&
@@ -250,8 +296,8 @@ export default class Mine extends Component {
250 296
           </View>
251 297
           <View className='draw-title'>图片质量</View>
252 298
           <View className='draw-mass'>
253
-            <View className='mass-same'>一般</View>
254
-            <View className='mass-high'>高清</View>
299
+            <View className='mass-same' style={this.state.mass == 0 ? 'border: 2px solid #0F84EC;' : ''} onClick={e => (this.changeMass(0))}>普通</View>
300
+            <View className='mass-high' style={this.state.mass == 1 ? 'border: 2px solid #0F84EC;' : ''} onClick={e => (this.changeMass(1))}>高清</View>
255 301
           </View>
256 302
           <View className='draw-title'>采样方式</View>
257 303
           <View className='draw-sampling'>
@@ -271,11 +317,15 @@ export default class Mine extends Component {
271 317
               onInput={e => (this.onInputNegative(e))}
272 318
               onBlur={e => (this.onBlurNegative(e))}
273 319
               maxlength='1000' />
320
+              {
321
+              this.state.negativeValue.length > 0 &&
322
+              <Image className='delete-draw-text' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679637370560.png' onClick={e => (this.deleteNegativeValue())}></Image>
323
+            }
274 324
             <View className='textarea-num' id='negative_prompt'>{this.state.negativeValue.length}/1000</View>
275 325
           </View>
276 326
         </View>
277 327
         <View className='generate-pictures' onClick={e => (this.generatePictures(e))} >
278
-          生成图片(消耗2积分)
328
+          生成图片(消耗{this.state.drawNum * 2 * (this.state.mass + 1)}积分)
279 329
         </View>
280 330
       </View>
281 331
     )

+ 12 - 3
src/pages/index/index.less

@@ -82,7 +82,7 @@
82 82
         background-color: rgba(255, 255, 255, .05);
83 83
         color: rgba(255, 255, 255, .5);
84 84
         min-height: 240px;
85
-        padding: 24rpx;
85
+        padding: 24rpx 24rpx 44rpx 24rpx;
86 86
       }
87 87
 
88 88
       .textarea-num {
@@ -90,6 +90,13 @@
90 90
         text-align: end;
91 91
         color: rgba(255, 255, 255, .5);
92 92
       }
93
+      .delete-draw-text{
94
+        position: absolute;
95
+        right: 5px;
96
+        bottom: 65px;
97
+        width: 40px;
98
+        height: 40px;
99
+      }
93 100
 
94 101
 
95 102
     }
@@ -202,6 +209,7 @@
202 209
       .measurement-info {
203 210
         margin: 0 20px;
204 211
         width: 116px;
212
+        box-sizing: border-box;
205 213
         height: 116px;
206 214
         background-color: rgba(255, 255, 255, .05);
207 215
         border-radius: 16px;
@@ -257,13 +265,13 @@
257 265
     .draw-mass {
258 266
       margin-top: 20px;
259 267
       display: flex;
260
-      opacity: 0.5;
261 268
       font-family: PingFangSC-Regular;
262 269
       font-size: 28px;
263 270
       color: rgba(255, 255, 255, .5);
264 271
 
265 272
       .mass-same {
266 273
         width: 150px;
274
+        box-sizing: border-box;
267 275
         height: 80px;
268 276
         line-height: 80px;
269 277
         text-align: center;
@@ -274,6 +282,7 @@
274 282
       .mass-high {
275 283
         width: 150px;
276 284
         height: 80px;
285
+        box-sizing: border-box;
277 286
         line-height: 80px;
278 287
         text-align: center;
279 288
         background-color: rgba(255, 255, 255, .05);
@@ -291,7 +300,7 @@
291 300
       color: rgba(255, 255, 255, .5);
292 301
 
293 302
       .sampling-same {
294
-
303
+        box-sizing: border-box;
295 304
         margin-top: 20px;
296 305
         margin-right: 20px;
297 306
         padding: 0 40px;

+ 3 - 1
src/pages/mine/index.config.js

@@ -1,3 +1,5 @@
1 1
 export default definePageConfig({
2
-  navigationBarTitleText: '我的'
2
+  navigationBarTitleText: '我的',
3
+  enableShareAppMessage: true,
4
+  enableShareTimeline: true ,
3 5
 })

+ 243 - 32
src/pages/mine/index.jsx

@@ -10,14 +10,39 @@ export default class Mine extends Component {
10 10
   state = {
11 11
     userInfo: {},
12 12
     type: 0,
13
-    infos: [],
14
-    total: 20,
13
+    cardinalInfos: [],//基数
14
+    evenInfos: [],//偶数
15
+    total: 0,
15 16
     page: 1,
16 17
     page_size: 20,
18
+    selection: false,
19
+    cardinalSelectedNum: 0,
20
+
17 21
   }
18 22
 
19 23
   componentDidShow () {
24
+    this.getInit(1)
20 25
     this.getUserInfo()
26
+  }
27
+  onShareAppMessage = (res) => {
28
+    let shareData = {
29
+      title: tool.shareTitle,
30
+      path: `/pages/index/index?c=${Taro.getStorageSync('user_id')}&s=rightTap`,
31
+      imageUrl: tool.shareImg
32
+    }
33
+    return shareData;
34
+  }
35
+  getInit () {
36
+    this.setState({
37
+      cardinalInfos: [],//基数
38
+      evenInfos: [],//偶数
39
+      total: 0,
40
+      page: 1,
41
+      page_size: 20,
42
+      selection: false,
43
+      cardinalSelectedNum: 0,
44
+      evenSelectedNum: 0,
45
+    })
21 46
     this.getMyDraw(1)
22 47
   }
23 48
   getUserInfo () {
@@ -30,22 +55,43 @@ export default class Mine extends Component {
30 55
     })
31 56
   }
32 57
   getMyDraw (page) {
58
+    Taro.showLoading({
59
+      title: '加载中',
60
+    })
33 61
     let params = {
34 62
       page: page,
35 63
       page_size: this.state.page_size,
36 64
     }
37
-    api.getMyDraw(params).then(res => {
65
+    let getInit = api.getMyDraw(params)
66
+    if (this.state.type == 1) {
67
+      getInit = api.getLikeList(params)
68
+    }
69
+    getInit.then(res => {
38 70
       if (res.code == 200) {
39
-        let infos = this.state.infos.concat(res.data.infos)
71
+        Taro.hideLoading()
72
+        res.data.infos.forEach((item, index) => {
73
+          item['select'] = false
74
+        })
75
+        let infos = res.data.infos
76
+        let _evenInfos = res.data.infos.filter((item, index) => {
77
+          return index % 2 == 1
78
+        })
79
+        let _cardinalInfos = res.data.infos.filter((item, index) => {
80
+          return index % 2 == 0
81
+        })
82
+        console.log(_cardinalInfos, '_cardinalInfos');
83
+        let cardinalInfos = this.state.cardinalInfos.concat(_cardinalInfos)
84
+        let evenInfos = this.state.evenInfos.concat(_evenInfos)
40 85
         this.setState({
41
-          infos: infos,
86
+          cardinalInfos: cardinalInfos,//基数
87
+          evenInfos: evenInfos,//偶数
42 88
           total: res.data.total
43 89
         })
44 90
       }
45 91
     })
46 92
   }
47 93
   onReachBottom () {
48
-    if (this.state.infos.length < this.state.total) {
94
+    if ((this.state.cardinalInfos.length + this.state.evenInfos.length) < this.state.total) {
49 95
       this.setState({
50 96
         page: this.state.page + 1
51 97
       })
@@ -56,11 +102,134 @@ export default class Mine extends Component {
56 102
   changeType (index) {
57 103
     this.setState({
58 104
       type: index
105
+    }, () => {
106
+      this.getInit()
59 107
     })
60 108
   }
61
-  toDetail(item){
109
+  //选中||详情页
110
+  toDetail (item, index, type) {
111
+    if (this.state.selection) {
112
+      if (type == 'cardinal') {
113
+        let _infos = this.state.cardinalInfos
114
+        _infos[index].select = !this.state.cardinalInfos[index].select
115
+        let infosSelect = _infos.filter(res => {
116
+          return res.select == true
117
+        })
118
+        console.log(infosSelect.length, 'infosSelect');
119
+        this.setState({
120
+          cardinalInfos: _infos,
121
+          cardinalSelectedNum: infosSelect.length
122
+        })
123
+      } else {
124
+        let _infos = this.state.evenInfos
125
+        _infos[index].select = !this.state.evenInfos[index].select
126
+        let infosSelect = _infos.filter(res => {
127
+          return res.select == true
128
+        })
129
+        console.log(infosSelect.length, 'infosSelect');
130
+        this.setState({
131
+          evenInfos: _infos,
132
+          evenSelectedNum: infosSelect.length
133
+        })
134
+      }
135
+
136
+    } else {
137
+      if (this.state.type == 1) {
138
+        Taro.navigateTo({
139
+          url: `/pages/communityDetail/index?task_id=${item.id}`
140
+        })
141
+      }else{
142
+        Taro.navigateTo({
143
+          url: `/pages/darwDetail/index?task_id=${item.task_id}&img_id=${item.id}`
144
+        })
145
+      }
146
+    }
147
+  }
148
+  cancelDelect () {
149
+    let _evenInfos = this.state.evenInfos
150
+    _evenInfos.forEach((item, index) => {
151
+      item.select = false
152
+    })
153
+    let _cardinalInfos = this.state.cardinalInfos
154
+    _cardinalInfos.forEach((item, index) => {
155
+      item.select = false
156
+    })
157
+    this.setState({
158
+      cardinalInfos: _cardinalInfos,
159
+      evenInfos: _evenInfos,
160
+      cardinalSelectedNum: 0,
161
+      evenSelectedNum: 0,
162
+      selection: !this.state.selection
163
+    })
164
+  }
165
+  delectiImg () {
166
+    let that = this
167
+    Taro.showModal({
168
+      title: '提示',
169
+      content: `确定删除这${this.state.cardinalSelectedNum + this.state.evenSelectedNum}张图片吗`,
170
+      success: function (res) {
171
+        if (res.confirm) {
172
+          that.deleteImg()
173
+        } else if (res.cancel) {
174
+          console.log('用户点击取消')
175
+        }
176
+      }
177
+    })
178
+  }
179
+  deleteImg () {
180
+    let deleteObj = []
181
+    this.state.cardinalInfos.forEach(res => {
182
+      if (res.select) {
183
+        console.log(res.id, 'res.id', res.select);
184
+        deleteObj.push(res.id)
185
+      }
186
+    })
187
+    this.state.evenInfos.forEach(res => {
188
+      if (res.select) {
189
+        console.log(res.id, 'res.id', res.select);
190
+        deleteObj.push(res.id)
191
+      }
192
+    })
193
+    console.log(deleteObj.join(','), 'deleteObj');
194
+    api.userDelImg({ img_ids: deleteObj.join(',') }).then(res => {
195
+      if (res.code == 200) {
196
+        Taro.showToast({
197
+          title: `删除成功`,
198
+          icon: 'none',
199
+        });
200
+        this.getInit(1)
201
+        this.getUserInfo()
202
+      }
203
+    })
204
+  }
205
+  //批量选择
206
+  changeSelection () {
207
+    if (this.state.selection) {
208
+      let _evenInfos = this.state.evenInfos
209
+      _evenInfos.forEach((item, index) => {
210
+        item.select = false
211
+      })
212
+      let _cardinalInfos = this.state.cardinalInfos
213
+      _cardinalInfos.forEach((item, index) => {
214
+        item.select = false
215
+      })
216
+      this.setState({
217
+        cardinalInfos: _cardinalInfos,
218
+        evenInfos: _evenInfos,
219
+        cardinalSelectedNum: 0,
220
+        evenSelectedNum: 0,
221
+        selection: !this.state.selection
222
+      })
223
+    } else {
224
+      this.setState({
225
+        selection: !this.state.selection
226
+      })
227
+    }
228
+  }
229
+
230
+  getEarnPoints () {
62 231
     Taro.navigateTo({
63
-      url: `/pages/darwDetail/index?task_id=${item.task_id}`
232
+      url: `/pages/earnPoints/index`
64 233
     })
65 234
   }
66 235
 
@@ -70,40 +239,82 @@ export default class Mine extends Component {
70 239
     return (
71 240
       <View className='mine'>
72 241
         <View className='user-info'>
73
-          <View className='user-top'>
74
-            <Image className='user-img' src={this.state.userInfo.head_img}></Image>
75
-            <View className='user-info-text'>
76
-              <View className='info-top'>
77
-                <View className='user-name'>{this.state.userInfo.user_name}</View>
78
-              </View>
79
-              <View className='info-bottom'>
80
-                <View className='integral'>积分:~</View>
242
+          <View className='user-bag'>
243
+            <View className='user-top'>
244
+              <Image className='user-img' src={this.state.userInfo.head_img}></Image>
245
+              <View className='user-info-text'>
246
+                <View className='info-top'>
247
+                  <View className='user-name'>{this.state.userInfo.user_name}</View>
248
+                </View>
249
+                <View className='info-bottom'>
250
+                  <View className='integral'>点券:{this.state.userInfo.total_coin}</View>
251
+                </View>
81 252
               </View>
82 253
             </View>
83
-          </View>
84
-          <View className='get-integral'>
85
-            <View className='inte-button'>获取积分</View>
86
-          </View>
87
-        </View>
88
-        <View className='type'>
89
-          <View className='type-content'>
90
-            <View className='works' style={this.state.type == 0 ? ' background-image: linear-gradient(-45deg, #4EC3F8 0%, #0F84EC 100%);color: #FFFFFF;' : ''} onClick={e => (this.changeType(0))}>作品</View>
91
-            <View className='like' style={this.state.type == 1 ? ' background-image: linear-gradient(-45deg, #4EC3F8 0%, #0F84EC 100%);color: #FFFFFF;' : ''} onClick={e => (this.changeType(1))}>喜欢</View>
254
+            <View className='get-integral'>
255
+              <View className='inte-button' onClick={e => (this.getEarnPoints())}>获取点券</View>
256
+            </View>
92 257
           </View>
93 258
         </View>
259
+
94 260
         <View className='work-list'>
95
-          <View className='work-num'>作品数量:{this.state.total}/1000</View>
261
+          <View className='type'>
262
+            <View className='type-content'>
263
+              <View className='works' style={this.state.type == 0 ? ' background-image: linear-gradient(-45deg, #4EC3F8 0%, #0F84EC 100%);color: #FFFFFF;' : ''} onClick={e => (this.changeType(0))}>作品</View>
264
+              <View className='like' style={this.state.type == 1 ? ' background-image: linear-gradient(-45deg, #4EC3F8 0%, #0F84EC 100%);color: #FFFFFF;' : ''} onClick={e => (this.changeType(1))}>喜欢</View>
265
+            </View>
266
+          </View>
267
+          {
268
+            this.state.type == 0 &&
269
+            <View className='work-num'>作品数量:{this.state.total}/{this.state.userInfo.stock_cnt}</View>
270
+          }
96 271
           <View className='work-list-info' >
97 272
             {
98
-              this.state.infos.map((item, index) => (
99
-                <View className='work-info' key={index} onClick={e=>(this.toDetail(item))}>
100
-                  <Image className='work-img' mode='widthFix' src={item.img}></Image>
101
-                  <View className='work-name'>{tool.ellipsis(item.img_info, 20)}</View>
102
-                </View>
103
-              ))
273
+              this.state.type == 0 &&
274
+              <View className='selection' onClick={e => (this.changeSelection())}>{!this.state.selection ? '批量选择' : '取消'}</View>
104 275
             }
276
+            <View className='selection-left'>
277
+              {
278
+                this.state.cardinalInfos.map((item, index) => (
279
+                  <View className='work-info' key={index} onClick={e => (this.toDetail(item, index, 'cardinal'))}>
280
+                    {
281
+                      this.state.selection &&
282
+                      <Image className='select' src={item.select ? 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679033915899.jpg' : 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679033897198.jpg'}></Image>
283
+                    }
284
+                    <Image className='work-img' lazyLoad mode='widthFix' src={item.img ? item.img : 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679305142417.png'}></Image>
285
+                    <View className='work-name'>{tool.ellipsis(item.img_info, 8)}</View>
286
+                  </View>
287
+                ))
288
+              }
289
+            </View>
290
+            <View className='selection-right'>
291
+              {
292
+                this.state.evenInfos.map((item, index) => (
293
+                  <View className='work-info' key={index} onClick={e => (this.toDetail(item, index, 'even'))}>
294
+                    {
295
+                      this.state.selection &&
296
+                      <Image className='select' src={item.select ? 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679033915899.jpg' : 'https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679033897198.jpg'}></Image>
297
+                    }
298
+                    <Image className='work-img' lazyLoad mode='widthFix' src={item.img}></Image>
299
+                    <View className='work-name'>{tool.ellipsis(item.img_info, 8)}</View>
300
+                  </View>
301
+                ))
302
+              }
303
+            </View>
304
+
105 305
           </View>
106 306
         </View>
307
+        {
308
+          this.state.selection &&
309
+          <View className='select-content'>
310
+            <View className='cancel' onClick={e => (this.cancelDelect())}>取消</View>
311
+            <View >当前已选中{this.state.cardinalSelectedNum + this.state.evenSelectedNum}张</View>
312
+            <View className='delect' onClick={e => (this.delectiImg())}>
313
+              <Image className='delect-icon' src='https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679037709270.png'></Image>
314
+              <View className='delect-text'>删除</View>
315
+            </View>
316
+          </View>
317
+        }
107 318
       </View>
108 319
     )
109 320
   }

+ 116 - 16
src/pages/mine/index.less

@@ -1,13 +1,19 @@
1 1
 .mine {
2 2
   min-height: 100vh;
3 3
   background-color: #041129;
4
-  padding-bottom: 120px;
4
+  // padding-bottom: 120px;
5 5
 
6 6
   .user-info {
7 7
     height: 326px;
8
-    background: #0F1A2F;
9
-    border-radius: 28px 28px 0 0;
10 8
     padding: 30px;
9
+    background-image: url(https://we-spa.oss-cn-shenzhen.aliyuncs.com/total_picture/1679475362928.png);
10
+
11
+    .user-bag {
12
+      display: flex;
13
+      justify-content: space-between;
14
+      align-items: center;
15
+
16
+    }
11 17
 
12 18
     .user-top {
13 19
       display: flex;
@@ -37,14 +43,13 @@
37 43
           .integral {
38 44
             font-family: PingFangSC-Regular;
39 45
             font-size: 28px;
40
-            color: #FFFFFF;
46
+            color: rgba(255, 255, 255, .75);
41 47
           }
42 48
         }
43 49
       }
44 50
     }
45 51
 
46 52
     .get-integral {
47
-      margin-top: 66px;
48 53
       display: flex;
49 54
       justify-content: center;
50 55
 
@@ -52,10 +57,11 @@
52 57
         width: 216px;
53 58
         height: 80px;
54 59
         line-height: 80px;
55
-        border: 2px solid #1489ED;
60
+        background-image: linear-gradient(-45deg, #4EC3F8 0%, #0F84EC 100%);
61
+        border-radius: 40px;
56 62
         font-family: PingFangSC-Regular;
57 63
         font-size: 32px;
58
-        color: #C6C6C6;
64
+        color: #FFFFFF;
59 65
         text-align: center;
60 66
 
61 67
       }
@@ -69,7 +75,7 @@
69 75
 
70 76
     .type-content {
71 77
       display: flex;
72
-      background: #0F1A2F;
78
+      background: rgba(255, 255, 255, .3);
73 79
       font-family: PingFangSC-Regular;
74 80
       font-size: 28px;
75 81
       color: rgba(255, 255, 255, .5);
@@ -96,27 +102,79 @@
96 102
   }
97 103
 
98 104
   .work-list {
99
-    margin-top: 70px;
100
-    padding: 0 30px;
105
+    min-height: 100vh;
106
+    background: #0F1A2F;
107
+    box-shadow: 12px 0 30px 0 #1E376D;
108
+    border-radius: 28px 28px 0 0;
109
+    margin-top: -150px;
110
+    padding: 28px 30px;
101 111
 
102 112
     .work-num {
113
+      margin-top: 48px;
103 114
       font-family: PingFangSC-Regular;
104 115
       font-size: 32px;
105 116
       color: #FFFFFF;
106 117
     }
107
-    .work-list-info{
118
+
119
+    .work-list-info {
120
+      width: 100%;
121
+      position: relative;
108 122
       margin-top: 40px;
123
+      column-gap: 5rpx;
124
+      column-count: 2;
125
+      /*每一格的高度*/
126
+
109 127
       display: flex;
110
-      flex-wrap: wrap;
111 128
       justify-content: space-between;
112
-      .work-info{
129
+
130
+      .selection {
131
+        position: absolute;
132
+        right: 0;
133
+        top: -94px;
134
+        width: 178px;
135
+        height: 64px;
136
+        line-height: 64px;
137
+        border-radius: 40px;
138
+        border: 2px solid #1489ED;
139
+        color: #1489ED;
140
+        font-family: PingFangSC-Regular;
141
+        font-size: 32px;
142
+        text-align: center;
143
+
144
+      }
145
+
146
+      .selection-left {
147
+        width: 330px;
148
+      }
149
+
150
+      .selection-right {
151
+        width: 330px;
152
+      }
153
+
154
+      .work-info {
113 155
         position: relative;
114 156
         margin-top: 10px;
115
-        width: 45%;
116
-        .work-img{
157
+
158
+        // width: 45%;
159
+
160
+        .select {
161
+          position: absolute;
162
+          background-color: white;
163
+          border-radius: 8px;
164
+          left: 20px;
165
+          top: 20px;
166
+          width: 40px;
167
+          height: 40px;
168
+        }
169
+
170
+        .work-img {
117 171
           width: 100%;
172
+          min-height: 180px;
173
+          display: block;
174
+          // height: 100%;
118 175
         }
119
-        .work-name{
176
+
177
+        .work-name {
120 178
           position: absolute;
121 179
           bottom: 0;
122 180
           left: 0;
@@ -130,4 +188,46 @@
130 188
       }
131 189
     }
132 190
   }
191
+
192
+  @media only screen and (max-width: 768px) {
193
+    .work-info {
194
+      width: calc(50% - 10px);
195
+    }
196
+  }
197
+
198
+  @media only screen and (max-width: 480px) {
199
+    .work-info {
200
+      width: 100%;
201
+    }
202
+  }
203
+
204
+  .select-content {
205
+    width: 100%;
206
+    padding: 20px 0;
207
+    background: rgba(11, 19, 37, .8);
208
+    position: fixed;
209
+    bottom: 0;
210
+    left: 0;
211
+    display: flex;
212
+    justify-content: space-between;
213
+    font-family: PingFangSC-Regular;
214
+    font-size: 32px;
215
+    color: #FFFFFF;
216
+
217
+    .cancel {
218
+      margin-left: 40px;
219
+    }
220
+
221
+    .delect {
222
+      margin-right: 40px;
223
+      display: flex;
224
+      align-items: center;
225
+
226
+      .delect-icon {
227
+        margin-right: 10px;
228
+        width: 40px;
229
+        height: 40px;
230
+      }
231
+    }
232
+  }
133 233
 }

+ 75 - 2
src/service/index.js

@@ -37,6 +37,13 @@ export const getMyDraw = data =>
37 37
     method: 'POST',
38 38
     data,
39 39
   });
40
+//获取我喜欢的作品
41
+export const getLikeList = data =>
42
+  Request({
43
+    url: '/api/get_like_list',
44
+    method: 'POST',
45
+    data,
46
+  });
40 47
 //获取画图详情页
41 48
 export const getDrawTaskStatus = data =>
42 49
   Request({
@@ -47,7 +54,73 @@ export const getDrawTaskStatus = data =>
47 54
 //获取画图详情页
48 55
 export const getUserInfo = data =>
49 56
   Request({
50
-    url: '/api/get_user_info',
57
+    url: '/api/get_my_wallet',
58
+    method: 'POST',
59
+    data,
60
+  });
61
+//获取点券列表
62
+export const getCoinTaskList = data =>
63
+  Request({
64
+    url: '/api/get_coin_task_list',
65
+    method: 'POST',
66
+    data,
67
+  });
68
+//完成任务
69
+export const finishTask = data =>
70
+  Request({
71
+    url: '/api/finish_task',
72
+    method: 'POST',
73
+    data,
74
+  });
75
+//获取广场列表
76
+export const getHubList = data =>
77
+  Request({
78
+    url: '/api/get_hub_list',
51 79
     method: 'POST',
52 80
     data,
53
-  });
81
+  });
82
+//获取广场详情页
83
+export const getImgDetail = data =>
84
+  Request({
85
+    url: '/api/get_img_detail',
86
+    method: 'POST',
87
+    data,
88
+  });
89
+//点赞
90
+export const userLike = data =>
91
+  Request({
92
+    url: '/api/user_like',
93
+    method: 'POST',
94
+    data,
95
+  });
96
+//获取分享二维码
97
+export const getWxCodeImg = data =>
98
+  Request({
99
+    url: '/api/get_wx_code_img',
100
+    method: 'POST',
101
+    data,
102
+  });
103
+//获取商品列表
104
+export const getShopList = data =>
105
+  Request({
106
+    url: '/api/get_shop_list',
107
+    method: 'POST',
108
+    data,
109
+  });
110
+//获取商品列表
111
+export const createOrder = data =>
112
+  Request({
113
+    url: '/api/wx_create_order',
114
+    method: 'POST',
115
+    data,
116
+  });
117
+//删除作品
118
+export const userDelImg = data =>
119
+  Request({
120
+    url: '/api/user_del_img',
121
+    method: 'POST',
122
+    data,
123
+  });
124
+ 
125
+
126
+