在 Yii 2.0 中,添加新的 RESTful API,用于新建资源(渲染表单数据)的实现
1、查看 rest/ActiveController.php,发现默认的动作方法列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /** * {@inheritdoc} */ public function actions() { return [ 'index' => [ 'class' => 'yii\rest\IndexAction' , 'modelClass' => $this ->modelClass, 'checkAccess' => [ $this , 'checkAccess' ], ], 'view' => [ 'class' => 'yii\rest\ViewAction' , 'modelClass' => $this ->modelClass, 'checkAccess' => [ $this , 'checkAccess' ], ], 'create' => [ 'class' => 'yii\rest\CreateAction' , 'modelClass' => $this ->modelClass, 'checkAccess' => [ $this , 'checkAccess' ], 'scenario' => $this ->createScenario, ], 'update' => [ 'class' => 'yii\rest\UpdateAction' , 'modelClass' => $this ->modelClass, 'checkAccess' => [ $this , 'checkAccess' ], 'scenario' => $this ->updateScenario, ], 'delete' => [ 'class' => 'yii\rest\DeleteAction' , 'modelClass' => $this ->modelClass, 'checkAccess' => [ $this , 'checkAccess' ], ], 'options' => [ 'class' => 'yii\rest\OptionsAction' , ], ]; } |
2、yii\rest\ActiveController 默认提供以下动作:
1 2 3 4 5 6 | index:按页列出资源 view:返回指定资源的详情 create:创建新的资源 update:更新一个存在的资源 delete:删除指定的资源 options:返回支持的 HTTP 方法 |
3、现有一个新的需求,在原型中已经体现,当 租户设置 – 选题紧急程度为关闭时,在新建选题页面中,字段:选题紧急程度不显示;,当 租户设置 – 选题紧急程度为开启时,在新建选题页面中,字段:选题紧急程度显示,如图1
4、在现阶段的实现中,RESTful API 仅提供了 3 个接口,分别为:
1 2 3 | create:创建新的资源 edit:编辑一个存在的资源(获取表单数据) update:更新一个存在的资源 |
5、因此,决定再添加一个新的接口,new:新建新的资源(获取表单数据),动作方法命名为:new,参考来源为 WordPress,之前的动作方法:edit,同样参考自 WordPress,如图2
1 | new:新建新的资源(获取表单数据) |
6、新建动作方法文件:api/rests/plan/NewAction.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | <?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace api\rests\plan; use Yii; use api\models\ConfigTask; use api\models\Plan; use api\models\redis\cmc_console\User as RedisCmcConsoleUser; use api\services\ConfigGroupService; /** * 新建选题(获取表单数据):/plans/new(plan/new) * * For more details and usage information on NewAction, see the [guide article on rest controllers](guide:rest-controllers). * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class NewAction extends Action { /** * News a new model. * @return array the model being displayed */ public function run() { if ( $this ->checkAccess) { call_user_func( $this ->checkAccess, $this ->id); } // 当前用户的身份实例,未认证用户则为 Null /* @var $identity RedisCmcConsoleUser */ $identity = Yii:: $app ->user->identity; /* @var $modelClass Plan */ $modelClass = $this ->modelClass; $model = new $modelClass ; $data = $model ->attributes; unset( $data [ 'id' ], $data [ 'group_id' ], $data [ 'create_user_id' ], $data [ 'create_name' ], $data [ 'emergency_is_open' ], $data [ 'material_asset_id' ], $data [ 'prev_status' ], $data [ 'is_not_isolated' ], $data [ 'is_deleted' ], $data [ 'created_at' ], $data [ 'updated_at' ], $data [ 'deleted_at' ]); // 基于租户ID获取状态为启用的租户配置数据 $configGroupData = ConfigGroupService::getDataEnabledByGroupId( $identity ->group_id); // 给请求参数赋默认值 $stringAttribute = [ 'title' , 'place' , 'opinion' , 'content' ]; $intAttribute = [ 'config_column_id' , 'occur_at' , 'ended_at' , 'importance' , 'emergency' , 'is_auto_task_create' , 'is_united' , 'status' ]; $arrayAttribute = [ 'keyword' ]; $time = time(); foreach ( $data as $key => $value ) { if (in_array( $key , $stringAttribute )) { if ( $key == 'place' ) { $data [ $key ] = $configGroupData [ 'base_location_name' ] . $configGroupData [ 'base_location_address' ]; } else { $data [ $key ] = '' ; } } if (in_array( $key , $intAttribute )) { if ( $key == 'importance' ) { $data [ $key ] = $model ::IMPORTANCE_DEFAULT; } elseif ( $key == 'emergency' ) { $data [ $key ] = $model ::EMERGENCY_DEFAULT; } elseif ( $key == 'occur_at' ) { $data [ $key ] = $time ; } elseif ( $key == 'ended_at' ) { $data [ $key ] = strtotime ( '+7 day' , time()); } elseif ( $key == 'status' ) { $data [ $key ] = $model ::STATUS_EDITED; } else { $data [ $key ] = 0; } } if (in_array( $key , $arrayAttribute )) { $data [ $key ] = []; } } // 素材的资源列表 $materialAssetsField = 'material_assets' ; $data [ $materialAssetsField ] = []; // 选题的参与用户列表 $planAttendedExecUsersField = 'plan_attended_exec_user_ids' ; $planAttendedAttendedUsersField = 'plan_attended_attended_user_ids' ; $data [ $planAttendedExecUsersField ] = []; $data [ $planAttendedAttendedUsersField ] = []; // 字段列表(是否允许编辑,0:否;1:是) $fields = []; $canEditableFields = [ 'title' , 'config_column_id' , 'occur_at' , 'place' , 'content' , 'ended_at' , 'importance' , 'is_auto_task_create' , 'keyword' , 'opinion' , 'is_united' , $materialAssetsField , $planAttendedExecUsersField , $planAttendedAttendedUsersField , 'status' , 'emergency' ]; // 字段列表(是否显示,0:否;1:是) $displayableFields = []; $canDisplayableFields = $canEditableFields ; // 基于租户ID查找资源(模型:任务配置)(状态:启用;是否默认:是)列表 $configTaskEnabledIsDefaultYesItems = ConfigTask::findAllEnabledIsDefaultYesByGroupId( $identity ->group_id); foreach ( $data as $fieldKey => $fieldValue ) { $fields [ $fieldKey ] = 0; $displayableFields [ $fieldKey ] = 0; if (in_array( $fieldKey , $canEditableFields )) { $fields [ $fieldKey ] = 1; // 是否自动创建任务 && 不存在默认的任务配置(是否允许编辑,0:否) if ( $fieldKey == 'is_auto_task_create' && empty ( $configTaskEnabledIsDefaultYesItems )) { $fields [ $fieldKey ] = 0; } // 紧急程度 && 租户配置数据的选题的紧急程度是否开启,0:否(是否允许编辑,0:否) if ( $fieldKey == 'emergency' && $configGroupData [ 'plan_emergency_is_open' ] == $model ::EMERGENCY_IS_OPEN_NO) { $fields [ $fieldKey ] = 0; } } if (in_array( $fieldKey , $canDisplayableFields )) { $displayableFields [ $fieldKey ] = 1; // 紧急程度 && 租户配置数据的选题的紧急程度是否开启,0:否(是否允许编辑,0:否) if ( $fieldKey == 'emergency' && $configGroupData [ 'plan_emergency_is_open' ] == $model ::EMERGENCY_IS_OPEN_NO) { $displayableFields [ $fieldKey ] = 0; } } } $data [ 'fields' ] = $fields ; $data [ 'displayable_fields' ] = $displayableFields ; return [ 'code' => 10000, 'message' => Yii::t( 'success' , '126046' ), 'data' => $data ]; } } |
7、在 Postman 中 GET:http://api.pcs-api.localhost/v1/plans/new ,响应参数,如图3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | { "code": 10000, "message": "新建选题(获取表单数据)成功", "data": { "title": "", "config_column_id": 0, "occur_at": 1576648175, "place": "南山区的基地名称详细地址", "content": "", "ended_at": 1577252975, "importance": 3, "emergency": 3, "is_auto_task_create": 0, "keyword": [], "opinion": "", "is_united": 0, "status": 1, "material_assets": [], "plan_attended_exec_user_ids": [], "plan_attended_attended_user_ids": [], "fields": { "title": 1, "config_column_id": 1, "occur_at": 1, "place": 1, "content": 1, "ended_at": 1, "importance": 1, "emergency": 1, "is_auto_task_create": 1, "keyword": 1, "opinion": 1, "is_united": 1, "status": 1, "material_assets": 1, "plan_attended_exec_user_ids": 1, "plan_attended_attended_user_ids": 1 }, "displayable_fields": { "title": 1, "config_column_id": 1, "occur_at": 1, "place": 1, "content": 1, "ended_at": 1, "importance": 1, "emergency": 1, "is_auto_task_create": 1, "keyword": 1, "opinion": 1, "is_united": 1, "status": 1, "material_assets": 1, "plan_attended_exec_user_ids": 1, "plan_attended_attended_user_ids": 1 } } } |
8、在响应参数中包含一些字段的默认值,前端与移动端在接收到响应数据后,可以基于其渲染表单数据,以保证前端与移动端的默认值的一致性,且默认值由接口控制,在需要调整默认值时,更为灵活。某个字段不存在默认值时,并未赋值为:null,原因在于如果赋值为:null,字段类型无法做到固定不变化。最终基于字段类型分别赋值为:空字符串、0、空数组。不过当某字段的类型为数字时,且其值为 0,客户端无法得知某字段是否具有默认值。
9、决定再添加一个字段:default_fields,用以标识某个字段的值是否为默认值。编辑动作方法文件:api/rests/plan/NewAction.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | <?php /** * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ */ namespace api\rests\plan; use Yii; use api\models\ConfigTask; use api\models\Plan; use api\models\redis\cmc_console\User as RedisCmcConsoleUser; use api\services\ConfigGroupService; /** * 新建选题(获取表单数据):/plans/new(plan/new) * * For more details and usage information on NewAction, see the [guide article on rest controllers](guide:rest-controllers). * * @author Qiang Wang <shuijingwanwq@163.com> * @since 1.0 */ class NewAction extends Action { /** * News a new model. * @return array the model being displayed */ public function run() { if ( $this ->checkAccess) { call_user_func( $this ->checkAccess, $this ->id); } // 当前用户的身份实例,未认证用户则为 Null /* @var $identity RedisCmcConsoleUser */ $identity = Yii:: $app ->user->identity; /* @var $modelClass Plan */ $modelClass = $this ->modelClass; $model = new $modelClass ; $data = $model ->attributes; unset( $data [ 'id' ], $data [ 'group_id' ], $data [ 'create_user_id' ], $data [ 'create_name' ], $data [ 'emergency_is_open' ], $data [ 'material_asset_id' ], $data [ 'prev_status' ], $data [ 'is_not_isolated' ], $data [ 'is_deleted' ], $data [ 'created_at' ], $data [ 'updated_at' ], $data [ 'deleted_at' ]); // 基于租户ID获取状态为启用的租户配置数据 $configGroupData = ConfigGroupService::getDataEnabledByGroupId( $identity ->group_id); // 给请求参数赋默认值 $stringAttribute = [ 'title' , 'place' , 'opinion' , 'content' ]; $intAttribute = [ 'config_column_id' , 'occur_at' , 'ended_at' , 'importance' , 'emergency' , 'is_auto_task_create' , 'is_united' , 'status' ]; $arrayAttribute = [ 'keyword' ]; $time = time(); foreach ( $data as $key => $value ) { if (in_array( $key , $stringAttribute )) { if ( $key == 'place' ) { $data [ $key ] = $configGroupData [ 'base_location_name' ] . $configGroupData [ 'base_location_address' ]; } else { $data [ $key ] = '' ; } } if (in_array( $key , $intAttribute )) { if ( $key == 'importance' ) { $data [ $key ] = $model ::IMPORTANCE_DEFAULT; } elseif ( $key == 'emergency' ) { $data [ $key ] = $model ::EMERGENCY_DEFAULT; } elseif ( $key == 'occur_at' ) { $data [ $key ] = $time ; } elseif ( $key == 'ended_at' ) { $data [ $key ] = strtotime ( '+7 day' , time()); } elseif ( $key == 'status' ) { $data [ $key ] = $model ::STATUS_EDITED; } else { $data [ $key ] = 0; } } if (in_array( $key , $arrayAttribute )) { $data [ $key ] = []; } } // 素材的资源列表 $materialAssetsField = 'material_assets' ; $data [ $materialAssetsField ] = []; // 选题的参与用户列表 $planAttendedExecUsersField = 'plan_attended_exec_user_ids' ; $planAttendedAttendedUsersField = 'plan_attended_attended_user_ids' ; $data [ $planAttendedExecUsersField ] = []; $data [ $planAttendedAttendedUsersField ] = []; // 字段列表(是否允许编辑,0:否;1:是) $fields = []; $canEditableFields = [ 'title' , 'config_column_id' , 'occur_at' , 'place' , 'content' , 'ended_at' , 'importance' , 'is_auto_task_create' , 'keyword' , 'opinion' , 'is_united' , $materialAssetsField , $planAttendedExecUsersField , $planAttendedAttendedUsersField , 'status' , 'emergency' ]; // 字段列表(是否默认,0:否;1:是) $defaultFields = []; $canDefaultFields = [ 'occur_at' , 'place' , 'ended_at' , 'importance' , 'emergency' , 'is_auto_task_create' , 'is_united' , 'status' ]; // 字段列表(是否显示,0:否;1:是) $displayableFields = []; $canDisplayableFields = $canEditableFields ; // 基于租户ID查找资源(模型:任务配置)(状态:启用;是否默认:是)列表 $configTaskEnabledIsDefaultYesItems = ConfigTask::findAllEnabledIsDefaultYesByGroupId( $identity ->group_id); foreach ( $data as $fieldKey => $fieldValue ) { $fields [ $fieldKey ] = 0; $displayableFields [ $fieldKey ] = 0; $defaultFields [ $fieldKey ] = 0; if (in_array( $fieldKey , $canEditableFields )) { $fields [ $fieldKey ] = 1; // 是否自动创建任务 && 不存在默认的任务配置(是否允许编辑,0:否) if ( $fieldKey == 'is_auto_task_create' && empty ( $configTaskEnabledIsDefaultYesItems )) { $fields [ $fieldKey ] = 0; } } if (in_array( $fieldKey , $canDefaultFields )) { $defaultFields [ $fieldKey ] = 1; } if (in_array( $fieldKey , $canDisplayableFields )) { $displayableFields [ $fieldKey ] = 1; // 紧急程度 && 租户配置数据的选题的紧急程度是否开启,0:否(是否允许编辑,0:否) if ( $fieldKey == 'emergency' && $configGroupData [ 'plan_emergency_is_open' ] == $model ::EMERGENCY_IS_OPEN_NO) { $displayableFields [ $fieldKey ] = 0; } } } $data [ 'fields' ] = $fields ; $data [ 'displayable_fields' ] = $displayableFields ; $data [ 'default_fields' ] = $defaultFields ; return [ 'code' => 10000, 'message' => Yii::t( 'success' , '126046' ), 'data' => $data ]; } } |
10、在 Postman 中 GET:http://api.pcs-api.localhost/v1/plans/new ,响应参数,如图4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | { "code": 10000, "message": "新建选题(获取表单数据)成功", "data": { "title": "", "config_column_id": 0, "occur_at": 1576720714, "place": "南山区的基地名称详细地址", "content": "", "ended_at": 1577325514, "importance": 3, "emergency": 3, "is_auto_task_create": 0, "keyword": [], "opinion": "", "is_united": 0, "status": 1, "material_assets": [], "plan_attended_exec_user_ids": [], "plan_attended_attended_user_ids": [], "fields": { "title": 1, "config_column_id": 1, "occur_at": 1, "place": 1, "content": 1, "ended_at": 1, "importance": 1, "emergency": 1, "is_auto_task_create": 1, "keyword": 1, "opinion": 1, "is_united": 1, "status": 1, "material_assets": 1, "plan_attended_exec_user_ids": 1, "plan_attended_attended_user_ids": 1 }, "displayable_fields": { "title": 1, "config_column_id": 1, "occur_at": 1, "place": 1, "content": 1, "ended_at": 1, "importance": 1, "emergency": 1, "is_auto_task_create": 1, "keyword": 1, "opinion": 1, "is_united": 1, "status": 1, "material_assets": 1, "plan_attended_exec_user_ids": 1, "plan_attended_attended_user_ids": 1 }, "default_fields": { "title": 0, "config_column_id": 0, "occur_at": 1, "place": 1, "content": 0, "ended_at": 1, "importance": 1, "emergency": 1, "is_auto_task_create": 1, "keyword": 0, "opinion": 0, "is_united": 1, "status": 1, "material_assets": 0, "plan_attended_exec_user_ids": 0, "plan_attended_attended_user_ids": 0 } } } |
11、字段是否显示,在设计时,存在 2 种方案,第 1 种方案为:响应参数中,emergency 可以存在|不存在;第 2 种方案为:响应参数中,emergency 一直存在,然后在 displayable_fields[’emergency’] 中设置其值为 1|0。最终决定使用第 2 种方案。原因在于,以保证响应参数的字段数量与类型上皆无变化,避免客户端对于字段是否存在的判断处理,降低客户端判断处理的复杂度。
12、上传选题素材时,前端的资源的可接受上传的文件扩展名列表,是由前端自行配置的,与接口基于约定实现,但是,其弊端在于,一旦后端有所调整,前端也需要相应调整,否则就不一致,现在决定在响应参数中添加:config,在此参数中包含新建选题表单所需要的一些限制性规则。查看参数配置文件:common/config/params-local.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | // 策划指挥系统接口 'pcsApi' => [ 'asset' => [ // 资源 'basePath' => 'E:/wwwroot/pcs-api/storage' , // BASE PATH 'tempDir' => '/tmp' , // TEMP DIR 'baseUrl' => '' , // BASE URL 'upload' => [ // 上传 'extensions' => 'ogg, pdf, xml, zip, gz, mp4, mp3, wav, webm, gif, jpeg, jpg, png, webp, svg, svgz, tiff, css, csv, txt, vcf, vcard, mov, qt, mkv, mk3d, mka, mks, wmv, flv' , // 可接受上传的文件扩展名列表 'mimeTypes' => 'application/ogg, application/pdf, application/xml, application/zip, application/gzip, audio/mp4, audio/mpeg, audio/ogg, audio/vnd.wave, audio/webm, image/gif, image/jpeg, image/png, image/webp, image/svg+xml, image/tiff, text/css, text/csv, text/plain, text/vcard, text/xml, video/mpeg, video/mp4, video/ogg, video/quicktime, video/webm, video/x-matroska, video/x-ms-wmv, video/x-flv' , // 可接受上传的 MIME 类型列表 'minSize' => null, // 上传文件所需最少多少 Byte 的大小 'maxSize' => 1024 * 1024 * 1024, // 上传文件所需最多多少 Byte 的大小 'maxFiles' => 10, // 给定属性最多能承载多少个文件 'scenario' => [ // 场景 'configGroupBaseLocationIcon' => [ // 租户设置的基地的图标 'extensions' => 'jpeg, jpg, png' , // 可接受上传的文件扩展名列表 'mimeTypes' => 'image/jpeg, image/png' , // 可接受上传的 MIME 类型列表 'minSize' => null, // 上传文件所需最少多少 Byte 的大小 'maxSize' => 1024 * 1024 * 2, // 上传文件所需最多多少 Byte 的大小 'maxFiles' => 2, // 给定属性最多能承载多少个文件 'minWidth' => 50, // 图片的最小宽度 'maxWidth' => 200, // 图片的最大宽度 'minHeight' => 50, // 图片的最小高度 'maxHeight' => 200, // 图片的最大高度 ], 'configUserGisAvatarCustomize' => [ // 用户设置的GIS大屏的自定义的头像 'extensions' => 'jpeg, jpg, png' , // 可接受上传的文件扩展名列表 'mimeTypes' => 'image/jpeg, image/png' , // 可接受上传的 MIME 类型列表 'minSize' => null, // 上传文件所需最少多少 Byte 的大小 'maxSize' => 1024 * 1024 * 2, // 上传文件所需最多多少 Byte 的大小 'maxFiles' => 2, // 给定属性最多能承载多少个文件 'minWidth' => 50, // 图片的最小宽度 'maxWidth' => 200, // 图片的最大宽度 'minHeight' => 50, // 图片的最小高度 'maxHeight' => 200, // 图片的最大高度 ], ], ], ], ], |
13、决定再添加一个字段:config,在此参数中包含新建选题表单所需要的一些限制性规则,配置参数的层级尽量控制在 3 级以内(既避免层级过深,且 Rap 文档工具仅支持 4 级)。后端的参数配置文件,可基于 Rancher 环境变量进行配置覆盖,继而可影响客户端。编辑动作方法文件:api/rests/plan/NewAction.php
1 2 3 4 5 6 7 8 | $assetUpload = Yii:: $app ->params[ 'pcsApi' ][ 'asset' ][ 'upload' ]; $data [ 'config' ][ 'asset_upload' ] = [ 'extensions' => $assetUpload [ 'extensions' ] ?? '' , 'mime_types' => $assetUpload [ 'mimeTypes' ] ?? '' , 'min_size' => $assetUpload [ 'minSize' ] ?? 0, 'max_size' => $assetUpload [ 'maxSize' ] ?? 0, 'max_files' => $assetUpload [ 'maxFiles' ] ?? 1, ]; |
1 2 3 4 5 6 7 8 9 | "config": { "asset_upload": { "extensions": "ogg, pdf, xml, zip, gz, mp4, mp3, wav, webm, gif, jpeg, jpg, png, webp, svg, svgz, tiff, css, csv, txt, vcf, vcard, mov, qt, mkv, mk3d, mka, mks, wmv, flv", "mime_types": "application/ogg, application/pdf, application/xml, application/zip, application/gzip, audio/mp4, audio/mpeg, audio/ogg, audio/vnd.wave, audio/webm, image/gif, image/jpeg, image/png, image/webp, image/svg+xml, image/tiff, text/css, text/csv, text/plain, text/vcard, text/xml, video/mpeg, video/mp4, video/ogg, video/quicktime, video/webm, video/x-matroska, video/x-ms-wmv, video/x-flv", "min_size": 0, "max_size": 1073741824, "max_files": 10 } } |
近期评论