Parcourir la source

feat: 添加广告 done

zhangyuting il y a 5 ans
Parent
commit
97404ebe7e

+ 233 - 0
src/app/api/miniAd.ts

@@ -0,0 +1,233 @@
+import { ExtendableContext } from 'koa'
+import { Response } from '@/app/types/response'
+import { MiniAdCampaignService } from '@/app/service/miniAdCampaignService'
+import { IApiMiniResponse, ICampaignInfo, ICampaignInfoResponse, IGetWXInfoResponse } from '@/app/types/miniAdResponse'
+import FormData from 'form-data'
+import { Encrypt } from '@/utils/encrypt'
+import { Random } from '@/utils/random'
+import * as fs from 'fs'
+
+export class MiniAd {
+  protected service: MiniAdCampaignService
+
+  constructor (ctx: ExtendableContext) {
+    this.service = new MiniAdCampaignService(ctx)
+  }
+
+  async getMiniInfo (ctx: ExtendableContext): Promise<Response<IGetWXInfoResponse>> {
+    const ret: Response<IGetWXInfoResponse> = {
+      code: 404,
+      msg: '没有数据',
+      data: null
+    }
+    try {
+      const ghID = ctx.request.header.ghID.toString()
+      if (!ghID) {
+        throw new Error('not found params')
+      }
+      const data = await this.service.getMiniInfo(ghID)
+      if (data) {
+        ret.code = 200
+        ret.msg = 'ok'
+        ret.data = data
+      }
+    } catch (e) {
+      console.log(e)
+      ret.code = 500
+      ret.msg = '操作失败'
+    }
+    return ret
+  }
+
+  async createCampaignInfo (ctx: ExtendableContext): Promise<Response<ICampaignInfoResponse>> {
+    const params = ctx.request.body
+    const ret: Response<ICampaignInfoResponse> = {
+      code: 404,
+      msg: '没有数据',
+      data: null
+    }
+    try {
+      if (!params.args) {
+        throw new Error('not found params')
+      }
+      const form = new FormData()
+      form.append('args', JSON.stringify(params.args))
+      const data = await this.service.createCampaignInfo(form)
+      if (data) {
+        ret.code = 200
+        ret.msg = 'ok'
+        ret.data = data
+      }
+    } catch (e) {
+      console.log(e)
+      ret.code = 500
+      ret.msg = '操作失败'
+    }
+    return ret
+  }
+
+  async snsImage (ctx: ExtendableContext): Promise<Response<ICampaignInfoResponse>> {
+    const params = ctx.request.body
+    const ret: Response<ICampaignInfoResponse> = {
+      code: 404,
+      msg: '没有数据',
+      data: null
+    }
+    try {
+      if (!params) {
+        throw new Error('not found params')
+      }
+      const form = new FormData()
+      let filename = await Encrypt.md5(Random.number(0, 999999).toString())
+      let fileMime = 'image/png'
+      form.append('token', 1242207897)
+      Object.entries(params).forEach(item => {
+        const k = item[0]
+        const v = item[1]
+        if (k === 'name') {
+          filename = v.toString()
+        } else if (k === 'type') {
+          fileMime = v.toString()
+        } else {
+          form.append(k, v)
+        }
+      })
+      const image = ctx.request.files.image_file
+
+      const path = image.path
+
+      form.append('image_file', fs.readFileSync(path, { encoding: 'binary' }), { contentType: params.type, filename: params.name })
+
+      const data = await this.service.snsImage(form)
+      if (data) {
+        console.log(data.body, data.headers)
+        // ret.code = 200
+        // ret.msg = 'ok'
+        // ret.data = data
+      }
+    } catch (e) {
+      console.log(e)
+      ret.code = 500
+      ret.msg = '操作失败'
+    }
+    return ret
+  }
+
+  async submitMaterialLibrary (ctx: ExtendableContext): Promise<Response<IApiMiniResponse>> {
+    const params = ctx.request.body
+    const ret: Response<IApiMiniResponse> = {
+      code: 404,
+      msg: '没有数据',
+      data: null
+    }
+    try {
+      if (!params.material_id || !params.cid) {
+        throw new Error('not found params')
+      }
+      const form = new FormData()
+      Object.entries(params).forEach(item => {
+        const k = item[0]
+        const v = item[1]
+        form.append(k, v)
+      })
+      const data = await this.service.submitMaterialLibrary(form)
+      if (data) {
+        ret.code = 200
+        ret.msg = 'ok'
+        ret.data = data
+      }
+    } catch (e) {
+      console.log(e)
+      ret.code = 500
+      ret.msg = '操作失败'
+    }
+    return ret
+  }
+
+  async getCampaignInfo (ctx: ExtendableContext): Promise<Response<ICampaignInfo>> {
+    const params = ctx.request.body
+    const ret: Response<ICampaignInfo> = {
+      code: 404,
+      msg: '没有数据',
+      data: null
+    }
+    try {
+      if (!params.cid) {
+        throw new Error('not found params')
+      }
+      const data = await this.service.getCampaignInfo(params.cid)
+      if (data) {
+        ret.code = 200
+        ret.msg = 'ok'
+        ret.data = data
+      }
+    } catch (e) {
+      console.log(e)
+      ret.code = 500
+      ret.msg = '操作失败'
+    }
+    return ret
+  }
+
+  async updateMaterial (ctx: ExtendableContext): Promise<Response<IApiMiniResponse>> {
+    const params = ctx.request.body
+    const ret: Response<IApiMiniResponse> = {
+      code: 404,
+      msg: '没有数据',
+      data: null
+    }
+    try {
+      if (!params.args) {
+        throw new Error('not found params')
+      }
+      const form = new FormData()
+      Object.entries(params).forEach(item => {
+        const k = item[0]
+        const v = item[1]
+        form.append(k, v)
+      })
+      const data = await this.service.updateMaterial(form)
+      if (data) {
+        ret.code = 200
+        ret.msg = 'ok'
+        ret.data = data
+      }
+    } catch (e) {
+      console.log(e)
+      ret.code = 500
+      ret.msg = '操作失败'
+    }
+    return ret
+  }
+
+  async submitCampaign (ctx: ExtendableContext): Promise<Response<IApiMiniResponse>> {
+    const params = ctx.request.body
+    const ret: Response<IApiMiniResponse> = {
+      code: 404,
+      msg: '没有数据',
+      data: null
+    }
+    try {
+      if (!params.args) {
+        throw new Error('not found params')
+      }
+      const form = new FormData()
+      Object.entries(params).forEach(item => {
+        const k = item[0]
+        const v = item[1]
+        form.append(k, v)
+      })
+      const data = await this.service.submitCampaign(form)
+      if (data) {
+        ret.code = 200
+        ret.msg = 'ok'
+        ret.data = data
+      }
+    } catch (e) {
+      console.log(e)
+      ret.code = 500
+      ret.msg = '操作失败'
+    }
+    return ret
+  }
+}

+ 0 - 38
src/app/api/miniGame.ts

@@ -1,38 +0,0 @@
-import { ExtendableContext } from 'koa'
-import { Response } from '@/app/types/response'
-import { MiniGameService } from '@/app/service/miniGameService'
-import { IGetWXInfoResponse } from '@/app/types/miniGameResponse'
-
-export class MiniGame {
-  protected service: MiniGameService
-  public prefix = '/mini_game'
-
-  constructor (ctx: ExtendableContext) {
-    this.service = new MiniGameService(ctx)
-  }
-
-  async getMiniInfo (ctx: ExtendableContext): Promise<Response<IGetWXInfoResponse>> {
-    const params = ctx.request.body
-    const ret: Response<IGetWXInfoResponse> = {
-      code: 404,
-      msg: '没有数据',
-      data: null
-    }
-    try {
-      console.log(params)
-      if (!params.ghID || !params.token) {
-        throw new Error('没有参数')
-      }
-      const data = await this.service.getMiniInfo(params.ghID, params.token)
-      if (data) {
-        ret.code = 200
-        ret.msg = 'ok'
-        ret.data = data
-      }
-    } catch (e) {
-      ret.code = 500
-      ret.msg = '操作失败'
-    }
-    return ret
-  }
-}

+ 1 - 0
src/app/api/oneLoadKey.ts

@@ -1,6 +1,7 @@
 import { OneLoadKeyService } from '@/app/service/oneLoadKeyService'
 import { ExtendableContext } from 'koa'
 import { Response } from '@/app/types/response'
+import { IData } from '../types/oneLoadKeyResponse'
 
 export class OneLoadKey {
   protected service: OneLoadKeyService

+ 4 - 3
src/app/middleware/cookie.ts

@@ -1,5 +1,6 @@
 import { ExtendableContext, Next } from 'koa'
 import { OneLoadKeyService } from '@/app/service/oneLoadKeyService'
+import { IOneLoadKeyResponse } from '../types/oneLoadKeyResponse'
 
 const miniGameService = new OneLoadKeyService()
 export class Cookie {
@@ -14,9 +15,9 @@ export class Cookie {
       data = await miniGameService.gen(ghID)
       await miniGameService.setCookie2Redis(ghID, data)
     }
-    ctx.request.body.cookie = data.data.cookie_as_string
-    ctx.request.body.token = data.data.token
-    ctx.request.body.ghID = ghID
+    ctx.request.header.cookie = data.data.cookie_as_string
+    ctx.request.header.token = data.data.token
+    ctx.request.header.ghID = ghID
     return next()
   }
 }

+ 7 - 8
src/app/service/miniGameBaseService.ts → src/app/service/miniAdBaseService.ts

@@ -1,12 +1,12 @@
 import got, { Response, Got } from 'got'
 import { ExtendableContext } from 'koa'
-import { IApiBaseResponse } from '@/app/types/miniGameResponse'
+import { IApiMiniResponse } from '@/app/types/miniAdResponse'
 
-export class MiniGameBaseService {
+export class MiniAdBaseService {
   protected api: Got
   constructor (ctx:ExtendableContext) {
-    const token:string = ctx.request.body.token
-    const cookie:string = ctx.request.body.cookie
+    const token:string = ctx.request.header.token.toString()
+    const cookie:string = ctx.request.header.cookie.toString()
     this.api = got.extend({
       prefixUrl: 'https://mp.weixin.qq.com/',
       timeout: 5000,
@@ -14,17 +14,16 @@ export class MiniGameBaseService {
       hooks: {
         beforeRequest: [
           async options => {
-            options.headers.referer = `https://mp.weixin.qq.com/wxopen/frame?t=promotion/ad_simple_frame&hidewording=1&page=campaign/edit&token=${token}&from_pos_type=999`
+            options.headers.referer = `https://mp.weixin.qq.com/wxopen/frame?t=promotion/ad_simple_frame&hidewording=1&page=campaign/edit&token=${token}&from_pos_type=0`
             options.headers.cookie = cookie
             options.headers.origin = 'https://mp.weixin.qq.com'
-            options.headers.contentType = 'application/x-www-form-urlencoded; charset=UTF-8'
-            options.headers.userAgent = 'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36'
+            options.headers['user-agent'] = 'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36'
             const { searchParams } = options.url
             searchParams.set('token', token)
           }
         ],
         afterResponse: [
-          (response: Response<IApiBaseResponse>) => {
+          (response: Response<IApiMiniResponse>) => {
             const { body, requestUrl } = response
             if (body && typeof body === 'object') {
               if (body.ret !== 0) {

+ 81 - 0
src/app/service/miniAdCampaignService.ts

@@ -0,0 +1,81 @@
+import {
+  IApiMiniResponse,
+  ICampaignInfoResponse,
+  IGetWXInfoResponse,
+  ISnsImageResponse
+  , ICampaignInfo
+} from '@/app/types/miniAdResponse'
+import { MiniAdBaseService } from './miniAdBaseService'
+import FormData from 'form-data'
+import { Response } from 'got'
+
+export class MiniAdCampaignService extends MiniAdBaseService {
+  // 获取小程序信息
+  async getMiniInfo (ghID: string): Promise<IGetWXInfoResponse> {
+    const params = {
+      action: 'check_weapp_id',
+      f: 'json',
+      lang: 'zh_CN',
+      ajax: 1,
+      gh_id: ghID,
+      check_type: 24
+    }
+    return this.api.get<IGetWXInfoResponse>('promotion/getlinkedwxa', {
+      searchParams: params,
+      resolveBodyOnly: true
+    })
+  }
+
+  // 创建计划
+  async createCampaignInfo (form:FormData):Promise<ICampaignInfoResponse> {
+    return this.api.post<ICampaignInfoResponse>('promotion/v3/create_campaign_info', {
+      body: form,
+      resolveBodyOnly: true
+    })
+  }
+
+  // 上传创意图片
+  async snsImage (form:FormData):Promise<Response> {
+    return this.api.post<ISnsImageResponse>('promotion/landingpage/snsimage', {
+      body: form,
+      decompress: false
+      // resolveBodyOnly: true
+    })
+  }
+
+  // 提交素材
+  async submitMaterialLibrary (form:FormData):Promise<IApiMiniResponse> {
+    return this.api.post<IApiMiniResponse>('promotion/material/material_library', {
+      body: form,
+      resolveBodyOnly: true,
+      decompress: false
+    })
+  }
+
+  // 获取创意数据
+  async getCampaignInfo (cid:number):Promise<ICampaignInfo> {
+    const params = {
+      args: `{"cid":${cid},"pos_type":101}`
+    }
+    return this.api.get<ICampaignInfo>('promotion/v3/get_campaign_info', {
+      searchParams: params,
+      resolveBodyOnly: true
+    })
+  }
+
+  // 更新素材
+  async updateMaterial (form:FormData):Promise<IApiMiniResponse> {
+    return this.api.post<IApiMiniResponse>('promotion/v3/update_material', {
+      body: form,
+      resolveBodyOnly: true
+    })
+  }
+
+  // 提交广告
+  async submitCampaign (form:FormData):Promise<IApiMiniResponse> {
+    return this.api.post<IApiMiniResponse>('promotion/v3/submit_campaign', {
+      body: form,
+      resolveBodyOnly: true
+    })
+  }
+}

+ 0 - 20
src/app/service/miniGameService.ts

@@ -1,20 +0,0 @@
-import { IGetWXInfoResponse } from '@/app/types/miniGameResponse'
-import { MiniGameBaseService } from './miniGameBaseService'
-
-export class MiniGameService extends MiniGameBaseService {
-  async getMiniInfo (ghID: string, token: string):Promise<IGetWXInfoResponse> {
-    const params = {
-      action: 'check_weapp_id',
-      f: 'json',
-      lang: 'zh_CN',
-      ajax: 1,
-      gh_id: ghID,
-      check_type: 24,
-      token: token
-    }
-    return this.api.get<IGetWXInfoResponse>('promotion/getlinkedwxa', {
-      searchParams: params,
-      resolveBodyOnly: true
-    })
-  }
-}

+ 1 - 1
src/app/service/oneLoadKeyService.ts

@@ -4,6 +4,7 @@ import { Encrypt } from '@/utils/encrypt'
 import config from 'config'
 import got from 'got'
 import redis from '@/app/db/redis'
+import { IOneLoadKeyResponse } from '../types/oneLoadKeyResponse'
 const token = config.get<string>('app.one_key_load.token')
 const client = config.get<string>('app.one_key_load.client')
 const redisKey = config.get<string>('app.cache.prefix')
@@ -17,7 +18,6 @@ export class OneLoadKeyService {
     const url = `${this.url}${ghID}/cookies`
     const params = await this.getParams()
     const result:IOneLoadKeyResponse = await got.get<IOneLoadKeyResponse>(url, { searchParams: params }).json()
-    console.log(result)
     if (result && result?.status.toLowerCase() === 'ok') {
       let cookieAsString = ''
       Object.entries(result.data.cookies).forEach(item => {

+ 111 - 0
src/app/types/miniAdRequest.ts

@@ -0,0 +1,111 @@
+// 创意
+export interface ICampaignInfo {
+  pos_type?: number;
+  product?: IProduct;
+  campaign?: ICampaign;
+  sub_product?: ISubProduct;
+  target_groups?: IITargetGroups[];
+  expected_ret?: number;
+  IMaterials?: IMaterials[];
+}
+
+export interface IMaterials {
+  tname?: string;
+  crt_size?: number;
+}
+
+export interface IITargetGroups {
+  target_group?: ITargetGroup;
+  ad_groups?: IIAdGroups[];
+}
+
+export interface IIAdGroups {
+  ad_group?: IAdGroup;
+  ad_target?: IAdTarget;
+}
+
+export interface IAdTarget {
+  mid?: number;
+  ad_behavior?: string;
+  education?: string;
+  device_price?: string;
+  area?: string;
+  travel_area?: string;
+  area_type?: string;
+  gender?: string;
+  sns_optimal_user_group?: string;
+  age?: string;
+  device_brand_model?: string;
+  businessinterest?: string;
+  app_behavior?: string;
+  os?: string;
+  marriage_status?: string;
+  wechatflowclass?: string;
+  connection?: string;
+  telcom?: string;
+  payment?: string;
+  game_consumption_level?: string;
+  custom_poi?: string;
+  weapp_version?: string;
+  oversea?: string;
+  in_dmp_audience?: string;
+  not_in_dmp_audience?: string;
+  behavior_interest?: string;
+  star_fans?: string;
+}
+
+export interface IAdGroup {
+  aid?: number;
+  backup_aid?: number;
+  aname?: string;
+  timeset?: string;
+  product_id?: string;
+  product_type?: string;
+  end_time?: number;
+  begin_time?: number;
+  strategy_opt?: string;
+  bid?: number;
+  budget?: number;
+  day_budget?: number;
+  contract_flag?: number;
+  pos_type?: number;
+  exposure_frequency?: number;
+  poi?: string;
+  expand_targeting_switch?: string;
+  expand_targeting_setting?: string;
+  cold_start_audience_id_list?: string;
+  time_mode?: number;
+  multi_slot_type?: number;
+  bid_strategy?: number;
+  auto_acquisition_switch?: number;
+  auto_acquisition_budget?: any;
+}
+
+export interface ITargetGroup {
+  mp_conf?: string;
+}
+
+export interface ISubProduct {
+  subordinate_product_id?: string;
+  product_type?: string;
+  product_id?: string;
+  spname?: string;
+}
+
+export interface ICampaign {
+  cid?: number;
+  ctype?: string;
+  cname?: string;
+  can_mix_product?: number;
+  end_time?: number;
+  begin_time?: number;
+  exposure_frequency?: number;
+}
+
+export interface IProduct {
+  product_type?: string;
+  product_id?: string;
+  product_info?: string;
+}
+
+// 上传创建图片

+ 448 - 0
src/app/types/miniAdResponse.ts

@@ -0,0 +1,448 @@
+export interface IApiMiniBaseResponse {
+  ret?: number
+  msg?: string;
+  cur_time?: number
+  display_message?: string;
+  err_ip?: string;
+  ret_msg?: string;
+  err_timestamp?: string;
+  data?:unknown
+}
+
+export interface IApiMiniResponse extends IApiMiniBaseResponse{
+  base_resp?: IApiMiniBaseResponse
+}
+
+// 获取微信信息接口
+export interface IGetWXInfoResponse<T = Record<string, unknown>> extends IApiMiniResponse {
+  appid?: string;
+  appseivicetype?: number;
+  check_msg?: string;
+  check_ret?: number;
+  headimgurl?: string;
+  nickname?: string;
+}
+
+// 广告创建-投放计划
+export interface ICampaignInfoResponse extends IApiMiniResponse {
+  sequence_id?: number;
+}
+
+// 上传图片
+export interface ISnsImageResponse extends IApiMiniResponse{
+  image_info?: ImageInfo
+}
+
+export interface ImageInfo {
+  image_url?: string;
+  thumb_url?: string;
+  height?: number;
+  width?: number;
+  size?: number;
+  image_md5?: string;
+  materialId?: number;
+}
+
+export interface Campaign {
+  acctid?: string;
+  advanced_version?: number;
+  api_source?: number;
+  appid?: string;
+  auto_release_time?: number;
+  begin_time?: number;
+  budget_allocation_type?: number;
+  can_mix_product?: number;
+  cid?: number;
+  cid_gdt?: number;
+  client?: string;
+  cname?: string;
+  create_time?: number;
+  ctype?: string;
+  day_budget?: number;
+  day_budget_limit_time?: number;
+  end_time?: number;
+  error_flag_sync_gdt?: number;
+  eval_image_result?: string;
+  eval_pass_times?: number;
+  eval_result?: string;
+  eval_times?: number;
+  exposure_frequency?: number;
+  gdt_status_change_time?: number;
+  last_user_update_time?: number;
+  model_version?: number;
+  modify_after_eval_times?: number;
+  modify_api_source?: number;
+  mpid?: string;
+  multi_creative?: number;
+  need_upd_gdt_status?: number;
+  op_time?: number;
+  outer_cid?: string;
+  present_activity_times?: number;
+  product_id?: string;
+  product_type?: string;
+  review_status?: number;
+  rpt_release_status?: number;
+  share_product?: number;
+  source?: number;
+  spid?: string;
+  status?: string;
+  subordinate_product_id?: string;
+  sync_status?: number;
+  sync_type?: number;
+  total_budget?: number;
+  uid?: number;
+  update_count?: number;
+}
+
+export interface Creative {
+  advanced_version?: number;
+  aid?: number;
+  api_source?: number;
+  cid?: number;
+  create_time?: number;
+  last_user_update_time?: number;
+  model_version?: number;
+  modify_api_source?: number;
+  op_time?: number;
+  review_msg?: string;
+  review_status?: number;
+  rid?: number;
+  spid?: string;
+  status?: string;
+  tid?: number;
+  tname?: string;
+  uid?: number;
+  update_count?: number;
+}
+
+export interface Material {
+  abandoned_by?: string;
+  api_source?: number;
+  app_redirect_way?: number;
+  appid?: string;
+  appmsg_info?: string;
+  auto_preview_time?: number;
+  backup_dest_url?: string;
+  button_action?: string;
+  button_page_id?: number;
+  button_page_type?: number;
+  button_param?: string;
+  channels_info?: string;
+  cid?: number;
+  create_time?: number;
+  crt_info?: string;
+  crt_size?: number;
+  crt_sync_status?: number;
+  definition_head_url?: string;
+  definition_nickname?: string;
+  desc?: string;
+  dest_conf?: string;
+  dest_type?: number;
+  dest_url?: string;
+  dest_url_redirect?: number;
+  dest_url_switch?: number;
+  ec_ext?: string;
+  ext_click_url?: string;
+  ext_exposure_url?: string;
+  ext_info?: string;
+  extend_info?: string;
+  filter_product_id?: string;
+  finder_event_info?: string;
+  fingerprint?: string;
+  head_click_param?: string;
+  head_click_right_bar_flag?: number;
+  head_click_type?: number;
+  image_url?: string;
+  industry_id?: number;
+  inner_link_name?: string;
+  inside_title?: string;
+  interaction?: number;
+  interaction_friend?: number;
+  is_hidden_comment?: number;
+  is_show_friend?: number;
+  is_use_definition?: number;
+  jump_info?: string;
+  landpage_mini_program_list?: string;
+  last_user_update_time?: number;
+  left_button_name?: string;
+  left_button_page_id?: number;
+  link_hidden?: number;
+  link_name?: string;
+  link_page_id?: number;
+  link_page_id_str?: string;
+  link_page_type?: number;
+  material_conf?: string;
+  material_version?: string;
+  model_version?: number;
+  modify_api_source?: number;
+  notify_adhelper_time?: number;
+  op_time?: number;
+  out_material_use_canvas_top?: number;
+  outer_tid?: string;
+  outside_title?: string;
+  override_canvas_head_option?: number;
+  page_id?: number;
+  page_id_str?: string;
+  page_track_url?: string;
+  page_type?: number;
+  permit_share?: number;
+  product_id?: string;
+  product_type?: string;
+  review_acquire_time?: number;
+  review_msg?: string;
+  review_status?: number;
+  reviewer?: string;
+  rid?: number;
+  right_button_name?: string;
+  right_button_page_id?: number;
+  scheme_url?: string;
+  show_complaint?: number;
+  show_first_comment?: number;
+  simple_canvas_sub_type?: number;
+  simple_canvas_webview_detail?: string;
+  simple_canvas_webview_type?: number;
+  simple_canvas_webview_url?: string;
+  sns_aid?: string;
+  sns_dynamic_show_text?: string;
+  sns_dynamic_show_type?: number;
+  sns_sync_time?: number;
+  source?: number;
+  spid?: string;
+  status?: string;
+  submit_time?: number;
+  subordinate_product_id?: string;
+  title?: string;
+  tmpl_id?: number;
+  tmpl_type?: number;
+  tname?: string;
+  uid?: number;
+  version?: number;
+  video_duration?: number;
+  watermark?: string;
+  watermark_text?: string;
+  white_list?: string;
+}
+
+export interface Product {
+  advertiser_label?: string;
+  api_source?: number;
+  cid?: number;
+  client?: string;
+  create_time?: number;
+  error_flag_sync_gdt?: number;
+  gdt_status_change_time?: number;
+  last_user_update_time?: number;
+  model_version?: number;
+  need_upd_gdt_status?: number;
+  op_time?: number;
+  pname?: string;
+  product_id?: string;
+  product_info?: string;
+  product_type?: string;
+  review_status?: number;
+  status?: string;
+  sync_status?: number;
+  sync_type?: number;
+  type?: number;
+  uid?: number;
+  update_count?: number;
+}
+
+export interface AdGroup {
+  acctid?: string;
+  ad_special_strategy_type?: number;
+  advanced_version?: number;
+  aid?: number;
+  aid_gdt?: number;
+  aindex?: number;
+  ams_category?: number;
+  ams_industry_id?: string;
+  aname?: string;
+  api_source?: number;
+  appid?: string;
+  audit_msg?: string;
+  audit_platform?: number;
+  auto_acquisition_budget?: number;
+  auto_acquisition_switch?: number;
+  begin_time?: number;
+  bid?: number;
+  bid_strategy?: number;
+  budget?: number;
+  budget_allocation_type?: number;
+  cate_root?: number;
+  category?: number;
+  change_bid?: number;
+  cid?: number;
+  cid_gdt?: number;
+  city_level?: number;
+  client?: string;
+  cold_start_audience_id_list?: string;
+  collect_phone?: number;
+  contract_flag?: number;
+  cost_type?: string;
+  create_time?: number;
+  created_by_appid?: string;
+  created_by_developer_appid?: number;
+  day_budget?: number;
+  deep_optimization_goal?: number;
+  dynamic_ad_product_id?: string;
+  dynamic_ad_type?: number;
+  dynamic_category_id?: number;
+  dynamic_product_ad_category?: number;
+  dynamic_recommend_type?: string;
+  end_time?: number;
+  error_flag_sync_gdt?: number;
+  expand_targeting_setting?: string;
+  expand_targeting_switch?: string;
+  exposure_frequency?: number;
+  flow_lock_status?: number;
+  gdt_status_change_time?: number;
+  get_task_time?: number;
+  industry_id?: string;
+  is_new?: number;
+  last_bid_time?: number;
+  last_user_update_time?: number;
+  local_business_mode?: number;
+  local_business_sub_mode?: number;
+  material_source_id?: number;
+  meta_class?: number;
+  mid?: number;
+  mid_gdt?: number;
+  model_version?: number;
+  modify_api_source?: number;
+  multi_pos?: number;
+  multi_slot_type?: number;
+  need_upd_gdt_status?: number;
+  need_wait_creative_status?: number;
+  notify_adhelper_time?: number;
+  op_time?: number;
+  op_user?: string;
+  optimization_goal?: number;
+  outer_aid?: string;
+  play_mode?: string;
+  poi?: string;
+  pos_type?: number;
+  product_id?: string;
+  product_type?: string;
+  review_status?: number;
+  review_time?: number;
+  schedule_time?: string;
+  siteset?: string;
+  source?: number;
+  spid?: string;
+  status?: string;
+  strategy_opt?: string;
+  subordinate_product_id?: string;
+  suspend_msg?: string;
+  sync_status?: number;
+  sync_type?: number;
+  time_mode?: number;
+  timeset?: string;
+  total_budget?: number;
+  type?: number;
+  uid?: number;
+  update_count?: number;
+  user_status?: number;
+  user_status_update_time?: number;
+  wechat_pay_status?: number;
+}
+
+export interface AdTarget {
+  ad_behavior?: string;
+  age?: string;
+  api_source?: number;
+  app_behavior?: string;
+  app_user?: string;
+  appid?: string;
+  area?: string;
+  behavior_interest?: string;
+  businessinterest?: string;
+  client?: string;
+  connection?: string;
+  create_time?: number;
+  custom_poi?: string;
+  description?: string;
+  device_brand_model?: string;
+  device_price?: string;
+  education?: string;
+  error_flag_sync_gdt?: number;
+  game_consumption_level?: string;
+  gdt_status_change_time?: number;
+  gender?: string;
+  history_behavior_interest?: string;
+  in_dmp_audience?: string;
+  in_wechat_number_pkg?: string;
+  in_wechat_smart_pkg?: string;
+  last_update_target_time?: number;
+  last_user_update_time?: number;
+  marriage_status?: string;
+  mid?: number;
+  mid_gdt?: number;
+  mname?: string;
+  mobile_price?: string;
+  model_version?: number;
+  modify_api_source?: number;
+  need_upd_gdt_status?: number;
+  not_in_dmp_audience?: string;
+  not_in_wechat_number_pkg?: string;
+  op_time?: number;
+  os?: string;
+  outer_mid?: string;
+  oversea?: string;
+  payment?: string;
+  placement?: string;
+  review_status?: number;
+  seed_audience?: string;
+  sns_optimal_user_group?: string;
+  spid?: string;
+  star_fans?: string;
+  status?: string;
+  sync_status?: number;
+  sync_type?: number;
+  target_flag?: number;
+  targetingext?: string;
+  targetingruledefinition?: string;
+  telcom?: string;
+  trade_info?: string;
+  trade_status?: number;
+  travel_area?: string;
+  uid?: number;
+  update_count?: number;
+  weapp_version?: string;
+  wechatflowclass?: string;
+}
+
+export interface AdGroups {
+  ad_group?: AdGroup;
+  ad_target?: AdTarget;
+}
+
+export interface TargetGroup2 {
+  cid?: number;
+  commodity_info?: string;
+  create_time?: number;
+  delete_flag?: number;
+  last_user_update_time?: number;
+  model_version?: number;
+  mp_conf?: string;
+  op_time?: number;
+  status?: string;
+  tgid?: number;
+  uid?: number;
+}
+
+export interface TargetGroup {
+  ad_groups?: AdGroup[];
+  target_group?: TargetGroup2;
+}
+
+export interface ICampaignInfo extends IApiMiniResponse{
+ data?:{
+   additional_args?: unknown;
+   campaign?: Campaign;
+   creatives?: Creative[];
+   materials?: Material[];
+   product?: Product;
+   target_groups?: TargetGroup[];
+ }
+}

+ 0 - 14
src/app/types/miniGameResponse.ts

@@ -1,14 +0,0 @@
-export interface IApiBaseResponse{
-  ret?:number
-  msg?: string;
-}
-
-// 获取微信信息接口
-export interface IGetWXInfoResponse<T = Record<string, unknown>> extends IApiBaseResponse{
-  appid?: string;
-  appseivicetype?: number;
-  check_msg?: string;
-  check_ret?: number;
-  headimgurl?: string;
-  nickname?: string;
-}

+ 3 - 3
src/app/types/oneLoadKeyResponse.ts

@@ -1,4 +1,4 @@
-interface IOneLoadKey {
+export interface IOneLoadKey {
   client?: string
   nonce?: number
   echostr?: number
@@ -6,14 +6,14 @@ interface IOneLoadKey {
   signature?: string
 }
 
-interface IOneLoadKeyResponse {
+export interface IOneLoadKeyResponse {
   status?: string;
   data?: IData;
 }
 
 /* 自动生成的 Interface */
 
-interface IData {
+export interface IData {
   type?: number;
   token?: string;
   cookies_status?: number;

+ 10 - 1
src/index.ts

@@ -6,13 +6,22 @@ import cors from '@koa/cors'
 import config from 'config'
 import router from '@/router'
 import { ConsoleRouters, Debug } from '@/utils/debug'
+import path from 'path'
 
 const app = new Koa()
 const port = config.get<number>('app.port')
 const appName = config.get<string>('app.name')
 const consoleRouters: ConsoleRouters[] = []
 
-app.use(koaBody())
+app.use(koaBody({
+  multipart: true,
+  formidable: {
+    // 上传目录
+    uploadDir: path.join(__dirname, '../public/uploads'),
+    // 保留文件扩展名
+    keepExtensions: true
+  }
+}))
 app.use(bodyParser())
 app.use(cors())
 app.use(router.routes()).use(router.allowedMethods())

+ 31 - 2
src/router/index.ts

@@ -3,7 +3,7 @@ import Router from 'koa-router'
 import { OneLoadKey } from '@/app/api/oneLoadKey'
 import { Index } from '@/app/provider'
 import { Request } from '@/app/middleware/request'
-import { MiniGame } from '@/app/api/miniGame'
+import { MiniAd } from '@/app/api/miniAd'
 
 const env = config.get<number>('app.env')
 const version = config.get<number>('app.version')
@@ -21,8 +21,37 @@ router.get('/one_load_key', Request.handle, async (ctx) => {
 })
 
 router.get('/get_wx_info', ...middleware, async (ctx) => {
-  const controller = new MiniGame(ctx)
+  const controller = new MiniAd(ctx)
   ctx.body = await controller.getMiniInfo(ctx)
 })
 
+router.post('/create_campaign_info', ...middleware, async (ctx) => {
+  const controller = new MiniAd(ctx)
+  ctx.body = await controller.createCampaignInfo(ctx)
+})
+
+router.post('/snsimage', ...middleware, async (ctx) => {
+  const controller = new MiniAd(ctx)
+  ctx.body = await controller.snsImage(ctx)
+})
+
+router.post('/submit_material_library', ...middleware, async (ctx) => {
+  const controller = new MiniAd(ctx)
+  ctx.body = await controller.submitMaterialLibrary(ctx)
+})
+
+router.get('/get_campaign_info', ...middleware, async (ctx) => {
+  const controller = new MiniAd(ctx)
+  ctx.body = await controller.getCampaignInfo(ctx)
+})
+
+router.post('/update_material', ...middleware, async (ctx) => {
+  const controller = new MiniAd(ctx)
+  ctx.body = await controller.updateMaterial(ctx)
+})
+
+router.post('/submit_campaign', ...middleware, async (ctx) => {
+  const controller = new MiniAd(ctx)
+  ctx.body = await controller.submitCampaign(ctx)
+})
 export default router