feat,wip: 입찰 기능 동작
This commit is contained in:
+2
-6
@@ -50,9 +50,7 @@ switch ($btn) {
|
||||
$db->update('general', [
|
||||
'turntime' => $db->sqleval('DATE_SUB(turntime, INTERVAL %i MINUTE)', $minute)
|
||||
], true);
|
||||
$db->update('auction', [
|
||||
'expire' => $db->sqleval('DATE_SUB(expire, INTERVAL %i MINUTE)', $minute)
|
||||
], true);
|
||||
//TODO: 경매 시간도 모두 당겨야함
|
||||
if ($locked) {
|
||||
unlock();
|
||||
}
|
||||
@@ -78,9 +76,7 @@ switch ($btn) {
|
||||
$db->update('general', [
|
||||
'turntime' => $db->sqleval('DATE_ADD(turntime, INTERVAL %i MINUTE)', $minute)
|
||||
], true);
|
||||
$db->update('auction', [
|
||||
'expire' => $db->sqleval('DATE_ADD(expire, INTERVAL %i MINUTE)', $minute)
|
||||
], true);
|
||||
//TODO: 경매시간도 모두 뒤로 미뤄야함
|
||||
if ($locked) {
|
||||
unlock();
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ namespace sammo;
|
||||
include "lib.php";
|
||||
include "func.php";
|
||||
|
||||
WebUtil::requireAJAX();
|
||||
|
||||
$session = Session::requireLogin([])->setReadOnly();
|
||||
|
||||
if(!class_exists('\\sammo\\DB')){
|
||||
|
||||
@@ -37,18 +37,32 @@ class GetActiveResourceAuctionList extends \sammo\BaseAPI
|
||||
$sellRiceList = [];
|
||||
/** @var AuctionInfo[] */
|
||||
$auctions = array_map(fn ($raw) => AuctionInfo::fromArray($raw), $db->query(
|
||||
'SELECT * FROM `ng_auction` WHERE `type` IN %ls AND `finished` != 0 ORDER BY `close_date` DESC',
|
||||
'SELECT * FROM `ng_auction` WHERE `type` IN %ls AND `finished` = 0 ORDER BY `close_date` DESC',
|
||||
[
|
||||
AuctionType::BuyRice->value,
|
||||
AuctionType::SellRice->value,
|
||||
]
|
||||
));
|
||||
|
||||
$recentLogs = getAuctionLogRecent(20);
|
||||
|
||||
|
||||
if (!$auctions) {
|
||||
return [
|
||||
'result' => true,
|
||||
'buyRice' => $buyRiceList,
|
||||
'sellRice' => $sellRiceList,
|
||||
'recentLogs' => $recentLogs,
|
||||
'generalID' => $session->generalID,
|
||||
];
|
||||
}
|
||||
|
||||
$auctionIDList = [];
|
||||
foreach ($auctions as $auction) {
|
||||
$auctionIDList[] = $auction->id;
|
||||
}
|
||||
|
||||
|
||||
$rawHighestBids = Util::convertArrayToDict($db->query(
|
||||
'SELECT bid.* FROM `ng_auction_bid` bid INNER JOIN (
|
||||
SELECT `auction_id`, MAX(`amount`) as `max_amount`
|
||||
@@ -87,7 +101,7 @@ class GetActiveResourceAuctionList extends \sammo\BaseAPI
|
||||
'amount' => $highestBid->amount,
|
||||
'date' => TimeUtil::format($highestBid->date, false),
|
||||
'generalID' => $highestBid->generalID,
|
||||
'generalName' => $highestBid->data->generalName,
|
||||
'generalName' => $highestBid->aux->generalName,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -98,8 +112,6 @@ class GetActiveResourceAuctionList extends \sammo\BaseAPI
|
||||
}
|
||||
}
|
||||
|
||||
$recentLogs = getAuctionLogRecent(20);
|
||||
|
||||
return [
|
||||
'result' => true,
|
||||
'buyRice' => $buyRiceList,
|
||||
|
||||
@@ -60,7 +60,7 @@ class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
|
||||
$responseBid = [];
|
||||
foreach ($bidList as $bid) {
|
||||
$responseBid[] = [
|
||||
'generalName' => $bid->data->generalName,
|
||||
'generalName' => $bid->aux->generalName,
|
||||
'amount' => $bid->amount,
|
||||
'isCallerHighestBidder' => $bid->generalID === $generalID,
|
||||
'date' => $bid->date,
|
||||
@@ -74,7 +74,7 @@ class GetUniqueItemAuctionDetail extends \sammo\BaseAPI
|
||||
'finished' => $auction->finished,
|
||||
'title' => $auction->detail->title,
|
||||
'target' => $auction->target,
|
||||
'isCallerHost' => $auction->openerGeneralID === $generalID,
|
||||
'isCallerHost' => $auction->hostGeneralID === $generalID,
|
||||
'hostName' => $auction->detail->hostName,
|
||||
'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt,
|
||||
'availableLatestBidCloseDate' => $auction->detail->availableLatestBidCloseDate,
|
||||
|
||||
@@ -69,12 +69,12 @@ class GetUniqueItemAuctionList extends \sammo\BaseAPI
|
||||
'finished' => $auction->finished,
|
||||
'title' => $auction->detail->title,
|
||||
'target' => $auction->target,
|
||||
'isCallerHost' => $auction->openerGeneralID === $generalID,
|
||||
'isCallerHost' => $auction->hostGeneralID === $generalID,
|
||||
'hostName' => $auction->detail->hostName,
|
||||
'remainCloseDateExtensionCnt' => $auction->detail->remainCloseDateExtensionCnt,
|
||||
'availableLatestBidCloseDate' => $auction->detail->availableLatestBidCloseDate,
|
||||
'highestBid' => [
|
||||
'generalName' => $highestBid->data->generalName,
|
||||
'generalName' => $highestBid->aux->generalName,
|
||||
'amount' => $highestBid->amount,
|
||||
'isCallerHighestBidder' => $highestBid->generalID === $generalID,
|
||||
'date' => $highestBid->date,
|
||||
|
||||
+35
-26
@@ -46,7 +46,7 @@ abstract class Auction
|
||||
{
|
||||
$db = DB::db();
|
||||
|
||||
if($this->_highestBid !== false){
|
||||
if ($this->_highestBid !== false) {
|
||||
return $this->_highestBid;
|
||||
}
|
||||
|
||||
@@ -75,11 +75,19 @@ abstract class Auction
|
||||
public function getMyPrevBid(): ?AuctionBidItem
|
||||
{
|
||||
$db = DB::db();
|
||||
$rawMyPrevBid = $db->queryFirstRow(
|
||||
'SELECT * FROM ng_auction_bid WHERE general_id = %i AND auction_id = %i ORDER BY `amount` DESC LIMIT 1',
|
||||
$this->general->getID(),
|
||||
$this->info->id
|
||||
);
|
||||
if (!$this->info->detail->isReverse) {
|
||||
$rawMyPrevBid = $db->queryFirstRow(
|
||||
'SELECT * FROM ng_auction_bid WHERE general_id = %i AND auction_id = %i ORDER BY `amount` DESC LIMIT 1',
|
||||
$this->general->getID(),
|
||||
$this->info->id
|
||||
);
|
||||
} else {
|
||||
$rawMyPrevBid = $db->queryFirstRow(
|
||||
'SELECT * FROM ng_auction_bid WHERE general_id = %i AND auction_id = %i ORDER BY `amount` ASC LIMIT 1',
|
||||
$this->general->getID(),
|
||||
$this->info->id
|
||||
);
|
||||
}
|
||||
if (!$rawMyPrevBid) {
|
||||
return null;
|
||||
}
|
||||
@@ -89,13 +97,14 @@ abstract class Auction
|
||||
public function __construct(protected readonly int $auctionID, protected General $general)
|
||||
{
|
||||
$db = DB::db();
|
||||
$rawAuctionInfo = $db->query('SELECT * FROM ng_auction WHERE id = %i', $auctionID);
|
||||
if ($rawAuctionInfo === null) {
|
||||
$rawAuctionInfo = $db->queryFirstRow('SELECT * FROM `ng_auction` WHERE id = %i', $auctionID);
|
||||
if (!$rawAuctionInfo) {
|
||||
throw new \RuntimeException("해당 경매가 없습니다: {$auctionID}");
|
||||
}
|
||||
$this->info = AuctionInfo::fromArray($rawAuctionInfo);
|
||||
if($this->info->type !== $this->auctionType){
|
||||
throw new \RuntimeException("잘못된 경매 타입입니다: {$this->info->type} != {$this->auctionType}");
|
||||
$thisAuctionType = static::$auctionType;
|
||||
if ($this->info->type !== $thisAuctionType) {
|
||||
throw new \RuntimeException("잘못된 경매 타입입니다: {$this->info->type->value} != {$thisAuctionType->value}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +113,9 @@ abstract class Auction
|
||||
return $this->info;
|
||||
}
|
||||
|
||||
public function shrinkCloseDate(?DateTimeInterface $date): ?string{
|
||||
if($date === null){
|
||||
public function shrinkCloseDate(?DateTimeInterface $date): ?string
|
||||
{
|
||||
if ($date === null) {
|
||||
$date = new DateTimeImmutable();
|
||||
}
|
||||
|
||||
@@ -196,7 +206,7 @@ abstract class Auction
|
||||
if ($isRollback) {
|
||||
$highestBid = $this->getHighestBid();
|
||||
if ($highestBid !== null) {
|
||||
$this->refundBid($highestBid, "{$this->info->title} 경매가 취소되었습니다.");
|
||||
$this->refundBid($highestBid, "{$this->info->id}번 {$this->info->detail->title} 경매가 취소되었습니다.");
|
||||
}
|
||||
$this->rollbackAuction();
|
||||
}
|
||||
@@ -216,15 +226,10 @@ abstract class Auction
|
||||
return '현재입찰가보다 높게 입찰해야 합니다.';
|
||||
}
|
||||
|
||||
$rawMyPrevBid = $db->queryFirstRow(
|
||||
'SELECT * FROM ng_auction_bid WHERE general_id = %i AND auction_id = %i ORDER BY `amount` DESC LIMIT 1',
|
||||
$general->getID(),
|
||||
$auctionInfo->id
|
||||
);
|
||||
if ($rawMyPrevBid === null) {
|
||||
$myPrevBid = $this->getMyPrevBid();
|
||||
if($myPrevBid !== null && $highestBid->no !== $myPrevBid->no){
|
||||
//이미 환불 받았으니 무효.
|
||||
$myPrevBid = null;
|
||||
} else {
|
||||
$myPrevBid = AuctionBidItem::fromArray($rawMyPrevBid);
|
||||
}
|
||||
|
||||
$morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0);
|
||||
@@ -269,8 +274,8 @@ abstract class Auction
|
||||
$general->increaseInheritancePoint(InheritanceKey::previous, -$morePoint);
|
||||
$general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $morePoint);
|
||||
|
||||
if ($myPrevBid === null || ($highestBid !== null && $myPrevBid->id !== $highestBid->id)) {
|
||||
$this->refundBid($highestBid, "{$auctionInfo->title} 경매에 상회입찰자가 나타났습니다.");
|
||||
if ($highestBid !== null && $myPrevBid === null) {
|
||||
$this->refundBid($highestBid, "{$auctionInfo->id}번 $auctionInfo->detail->title}에 상회입찰자가 나타났습니다.");
|
||||
}
|
||||
$general->applyDB($db);
|
||||
return null;
|
||||
@@ -326,6 +331,10 @@ abstract class Auction
|
||||
|
||||
|
||||
$myPrevBid = $this->getMyPrevBid();
|
||||
if($myPrevBid !== null && $highestBid->no !== $myPrevBid->no){
|
||||
//이미 환불 받았으니 무효.
|
||||
$myPrevBid = null;
|
||||
}
|
||||
|
||||
$morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0);
|
||||
$resType = $auctionInfo->reqResource;
|
||||
@@ -361,8 +370,8 @@ abstract class Auction
|
||||
|
||||
$general->increaseVar($resType->value, -$morePoint);
|
||||
|
||||
if ($myPrevBid === null || ($highestBid !== null && $myPrevBid->id !== $highestBid->id)) {
|
||||
$this->refundBid($highestBid, "{$auctionInfo->title} 경매에 상회입찰자가 나타났습니다.");
|
||||
if ($highestBid !== null && $myPrevBid === null) {
|
||||
$this->refundBid($highestBid, "{$auctionInfo->id}번 {$auctionInfo->detail->title}에 상회입찰자가 나타났습니다.");
|
||||
}
|
||||
$general->applyDB($db);
|
||||
return null;
|
||||
@@ -382,7 +391,7 @@ abstract class Auction
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($highestBid->data->tryExtendCloseDate) {
|
||||
if ($highestBid->aux->tryExtendCloseDate) {
|
||||
//연장 요청이 있었다.
|
||||
$extendedCloseDate = $this->info->closeDate->add(TimeUtil::secondsToDateInterval(
|
||||
max(static::MIN_EXTENSION_MINUTES_BY_EXTENSION_QUERY, $this->info->turnTerm * static::COEFF_EXTENSION_MINUTES_BY_EXTENSION_QUERY) * 60
|
||||
|
||||
@@ -45,7 +45,7 @@ abstract class AuctionBasicResource extends Auction
|
||||
$db = DB::db();
|
||||
if (!($general instanceof DummyGeneral)) {
|
||||
$prevAuctionID = $db->queryFirstField(
|
||||
'SELECT id FROM ng_auction WHERE opener_general_id = %i AND finished = 0 AND `type` IN %ls',
|
||||
'SELECT id FROM ng_auction WHERE host_general_id = %i AND finished = 0 AND `type` IN %ls',
|
||||
$general->getID(),
|
||||
[AuctionType::BuyRice->value, AuctionType::SellRice->value],
|
||||
);
|
||||
@@ -88,7 +88,7 @@ abstract class AuctionBasicResource extends Auction
|
||||
$general->increaseVarWithLimit($hostRes->value, -$amount, 0);
|
||||
$general->applyDB($db);
|
||||
|
||||
return new self($openResult, $general);
|
||||
return new static($openResult, $general);
|
||||
}
|
||||
|
||||
static public function genDummy(): DummyGeneral
|
||||
@@ -102,12 +102,12 @@ abstract class AuctionBasicResource extends Auction
|
||||
|
||||
protected function rollbackAuction(): void
|
||||
{
|
||||
if ($this->general->getID() === $this->info->openerGeneralID) {
|
||||
if ($this->general->getID() === $this->info->hostGeneralID) {
|
||||
$auctionHost = $this->general;
|
||||
} else if ($this->info->openerGeneralID == 0) {
|
||||
} else if ($this->info->hostGeneralID == 0) {
|
||||
$auctionHost = $this->genDummy();
|
||||
} else {
|
||||
$auctionHost = General::createGeneralObjFromDB($this->info->openerGeneralID);
|
||||
$auctionHost = General::createGeneralObjFromDB($this->info->hostGeneralID);
|
||||
}
|
||||
|
||||
$hostRes = static::$hostRes;
|
||||
@@ -143,12 +143,12 @@ abstract class AuctionBasicResource extends Auction
|
||||
|
||||
protected function finishAuction(AuctionBidItem $highestBid, General $bidder): ?string
|
||||
{
|
||||
if ($this->general->getID() === $this->info->openerGeneralID) {
|
||||
if ($this->general->getID() === $this->info->hostGeneralID) {
|
||||
$auctionHost = $this->general;
|
||||
} else if ($this->info->openerGeneralID == 0) {
|
||||
} else if ($this->info->hostGeneralID == 0) {
|
||||
$auctionHost = $this->genDummy();
|
||||
} else {
|
||||
$auctionHost = General::createGeneralObjFromDB($this->info->openerGeneralID);
|
||||
$auctionHost = General::createGeneralObjFromDB($this->info->hostGeneralID);
|
||||
}
|
||||
|
||||
$highestBid = $this->getHighestBid();
|
||||
@@ -215,7 +215,7 @@ abstract class AuctionBasicResource extends Auction
|
||||
|
||||
public function bid(int $amount, bool $tryExtendCloseDate = false): ?string
|
||||
{
|
||||
if ($this->info->openerGeneralID === $this->general->getID()) {
|
||||
if ($this->info->hostGeneralID === $this->general->getID()) {
|
||||
return '자신이 연 경매에 입찰할 수 없습니다.';
|
||||
}
|
||||
$result = $this->_bid($amount, $tryExtendCloseDate);
|
||||
@@ -232,5 +232,7 @@ abstract class AuctionBasicResource extends Auction
|
||||
$date = (new DateTimeImmutable())->add(TimeUtil::secondsToDateInterval($turnTerm * 60));
|
||||
$this->shrinkCloseDate($date);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class AuctionUniqueItem extends Auction
|
||||
}
|
||||
|
||||
$prevAuctionID = $db->queryFirstField(
|
||||
'SELECT id FROM ng_auction WHERE opener_general_id = %i AND finished = 0 AND `type` = %s',
|
||||
'SELECT id FROM ng_auction WHERE host_general_id = %i AND finished = 0 AND `type` = %s',
|
||||
$general->getID(),
|
||||
AuctionType::UniqueItem->value,
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@ class AuctionBidItem extends DTO
|
||||
{
|
||||
public function __construct(
|
||||
#[NullIsUndefined]
|
||||
public ?int $id,
|
||||
public ?int $no,
|
||||
#[RawName('auction_id')]
|
||||
public int $auctionID,
|
||||
public ?int $owner,
|
||||
@@ -25,7 +25,7 @@ class AuctionBidItem extends DTO
|
||||
#[Convert(DateTimeConverter::class)]
|
||||
public \DateTimeImmutable $date,
|
||||
#[JsonString]
|
||||
public AuctionBidItemData $data,
|
||||
public AuctionBidItemData $aux,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class AuctionInfo extends DTO
|
||||
public ?string $target,
|
||||
#[RawName('host_general_id')]
|
||||
public int $hostGeneralID,
|
||||
#[RawName('reqResource')]
|
||||
#[RawName('req_resource')]
|
||||
public ResourceType $reqResource,
|
||||
|
||||
#[RawName('open_date')]
|
||||
|
||||
@@ -68,4 +68,5 @@ DROP TABLE IF EXISTS ng_betting;
|
||||
DROP TABLE IF EXISTS vote;
|
||||
DROP TABLE IF EXISTS vote_comment;
|
||||
|
||||
DROP TABLE IF EXISTS `ng_auction`;
|
||||
DROP TABLE IF EXISTS `ng_auction_bid`;
|
||||
@@ -16,5 +16,5 @@
|
||||
<?=$btnBegin??''?><a href='b_battleCenter.php' target='_blank' class='open-window commandButton <?=$btnClass??""?> <?= $showSecret ? '' : 'disabled' ?>'>감 찰 부</a><?=$btnEnd??''?>
|
||||
<?=$btnBegin??''?><a href='v_inheritPoint.php' class='commandButton <?=$btnClass??""?>'>유산 관리</a><?=$btnEnd??''?>
|
||||
<?=$btnBegin??''?><a href='b_myPage.php' class='commandButton <?=$btnClass??""?>'>내 정보&설정</a><?=$btnEnd??''?>
|
||||
<?=$btnBegin??''?><a href='b_auction.php' target='_blank' class='open-window commandButton <?=$btnClass??""?>'>거 래 장</a><?=$btnEnd??''?>
|
||||
<?=$btnBegin??''?><a href='v_auction.php' target='_blank' class='open-window commandButton <?=$btnClass??""?>'>거 래 장</a><?=$btnEnd??''?>
|
||||
<?=$btnBegin??''?><a href='b_betting.php' target='_blank' class='open-window <?=$btnClassForBetting??""?>'>베 팅 장</a><?=$btnEnd??''?>
|
||||
+24
-3
@@ -1,11 +1,32 @@
|
||||
<template>
|
||||
<div>테스트</div>
|
||||
<BContainer id="container" :toast="{ root: true }" class="bg0">
|
||||
<TopBackBar type="normal" :title="isResAuction ? '경매장' : '유니크 경매장'" :reloadable="true" @reload="tryReload">
|
||||
<BButton @click="isResAuction = true">금/쌀</BButton>
|
||||
<BButton @click="isResAuction = false">유니크</BButton>
|
||||
</TopBackBar>
|
||||
<AuctionResource v-if="isResAuction"></AuctionResource>
|
||||
<AuctionUniqueItem v-else></AuctionUniqueItem>
|
||||
<BottomBar></BottomBar>
|
||||
</BContainer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
/*declare const staticValues: {
|
||||
serverID: string,
|
||||
serverNick: string,
|
||||
turnterm: number,
|
||||
serverNick: string,
|
||||
};*/
|
||||
</script>
|
||||
<script lang="ts" setup></script>
|
||||
<script lang="ts" setup>
|
||||
import { BButton, BContainer } from "bootstrap-vue-3";
|
||||
import TopBackBar from "@/components/TopBackBar.vue";
|
||||
import BottomBar from "./components/BottomBar.vue";
|
||||
import AuctionResource from "@/components/AuctionResource.vue";
|
||||
import AuctionUniqueItem from "@/components/AuctionUniqueItem.vue";
|
||||
import { ref } from "vue";
|
||||
|
||||
const isResAuction = ref(true);
|
||||
|
||||
function tryReload() {
|
||||
console.log('갱신');
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"common": "common_deprecated.ts"
|
||||
},
|
||||
"ingame_vue": {
|
||||
"v_auction": "v_auction.ts",
|
||||
"v_inheritPoint": "v_inheritPoint.ts",
|
||||
"v_board": "v_board.ts",
|
||||
"v_cachedMap": "v_cachedMap",
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
<template>
|
||||
<div class="bg0">
|
||||
<div class="bg2">거래장</div>
|
||||
<div style="background-color: orange">쌀 구매</div>
|
||||
<div class="row gx-0">
|
||||
<div class="col">번호</div>
|
||||
<div class="col">판매자</div>
|
||||
<div class="col">물품</div>
|
||||
<div class="col">수량</div>
|
||||
<div class="col">시작 구매가</div>
|
||||
<div class="col">현재 구매가</div>
|
||||
<div class="col">즉시 구매가</div>
|
||||
<div class="col">단가</div>
|
||||
<div class="col">구매 예정자</div>
|
||||
<div class="col">거래 종료</div>
|
||||
</div>
|
||||
<div v-for="auction of buyRice" :key="auction.id" class="row gx-0" @click="selectedBuyRiceAuction = auction">
|
||||
<div class="col">{{ auction.id }}</div>
|
||||
<div class="col">{{ auction.hostName }}</div>
|
||||
<div class="col">쌀</div>
|
||||
<div class="col">{{ auction.amount }}</div>
|
||||
<div class="col">{{ auction.startBidAmount }}</div>
|
||||
<div class="col">{{ auction.highestBid ? auction.highestBid.amount : "-" }}</div>
|
||||
<div class="col">{{ auction.finishBidAmount }}</div>
|
||||
<div class="col">{{ auction.highestBid ? auction.highestBid.amount / auction.amount : "-" }}</div>
|
||||
<div class="col">{{ auction.highestBid ? auction.highestBid.generalName : "-" }}</div>
|
||||
<div class="col">{{ auction.closeDate }}</div>
|
||||
</div>
|
||||
<div v-if="selectedBuyRiceAuction !== undefined">
|
||||
<div class="col">{{ selectedBuyRiceAuction.id }}번 쌀 {{ selectedBuyRiceAuction.amount }} 경매에</div>
|
||||
<div class="col">
|
||||
<NumberInputWithInfo
|
||||
v-model="bidAmountBuyRiceAuction"
|
||||
:int="true"
|
||||
:min="selectedBuyRiceAuction.startBidAmount"
|
||||
:max="selectedBuyRiceAuction.finishBidAmount"
|
||||
title="금"
|
||||
:step="10"
|
||||
></NumberInputWithInfo>
|
||||
</div>
|
||||
<div class="col"><BButton @click="bidBuyRiceAuction">입찰</BButton></div>
|
||||
</div>
|
||||
|
||||
<div style="background-color: skyblue">쌀 판매</div>
|
||||
<div class="row gx-0">
|
||||
<div class="col">번호</div>
|
||||
<div class="col">판매자</div>
|
||||
<div class="col">물품</div>
|
||||
<div class="col">수량</div>
|
||||
<div class="col">시작 구매가</div>
|
||||
<div class="col">현재 구매가</div>
|
||||
<div class="col">즉시 구매가</div>
|
||||
<div class="col">단가</div>
|
||||
<div class="col">구매 예정자</div>
|
||||
<div class="col">거래 종료</div>
|
||||
</div>
|
||||
<div v-for="auction of sellRice" :key="auction.id" class="row gx-0" @click="selectedSellRiceAuction = auction">
|
||||
<div class="col">{{ auction.id }}</div>
|
||||
<div class="col">{{ auction.hostName }}</div>
|
||||
<div class="col">금</div>
|
||||
<div class="col">{{ auction.amount }}</div>
|
||||
<div class="col">{{ auction.startBidAmount }}</div>
|
||||
<div class="col">{{ auction.highestBid ? auction.highestBid.amount : "-" }}</div>
|
||||
<div class="col">{{ auction.finishBidAmount }}</div>
|
||||
<div class="col">{{ auction.highestBid ? auction.highestBid.amount / auction.amount : "-" }}</div>
|
||||
<div class="col">{{ auction.highestBid ? auction.highestBid.generalName : "-" }}</div>
|
||||
<div class="col">{{ auction.closeDate }}</div>
|
||||
</div>
|
||||
<div v-if="selectedSellRiceAuction !== undefined" class="row">
|
||||
<div class="col">{{ selectedSellRiceAuction.id }}번 금 {{ selectedSellRiceAuction.amount }} 경매에</div>
|
||||
<div class="col">
|
||||
<NumberInputWithInfo
|
||||
v-model="bidAmountSellRiceAuction"
|
||||
:int="true"
|
||||
:min="selectedSellRiceAuction.startBidAmount"
|
||||
:max="selectedSellRiceAuction.finishBidAmount"
|
||||
title="쌀"
|
||||
:step="10"
|
||||
></NumberInputWithInfo>
|
||||
</div>
|
||||
<div class="col"><BButton @click="bidSellRiceAuction">입찰</BButton></div>
|
||||
</div>
|
||||
|
||||
<div>경매 등록</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
매물
|
||||
<BButtonGroup>
|
||||
<BButton :pressed="openAuctionInfo.type == 'buyRice'" @click="openAuctionInfo.type = 'buyRice'"> 쌀 </BButton>
|
||||
<BButton :pressed="openAuctionInfo.type == 'sellRice'" @click="openAuctionInfo.type = 'sellRice'">
|
||||
금
|
||||
</BButton>
|
||||
</BButtonGroup>
|
||||
</div>
|
||||
<div class="col">
|
||||
<NumberInputWithInfo
|
||||
v-model="openAuctionInfo.amount"
|
||||
:int="true"
|
||||
:min="100"
|
||||
:max="10000"
|
||||
title="수량"
|
||||
:step="10"
|
||||
></NumberInputWithInfo>
|
||||
</div>
|
||||
<div class="col">
|
||||
<NumberInputWithInfo
|
||||
v-model="openAuctionInfo.startBidAmount"
|
||||
:int="true"
|
||||
:min="100"
|
||||
:max="10000"
|
||||
title="시작구매가"
|
||||
:step="10"
|
||||
></NumberInputWithInfo>
|
||||
</div>
|
||||
<div class="col">
|
||||
<NumberInputWithInfo
|
||||
v-model="openAuctionInfo.finishBidAmount"
|
||||
:int="true"
|
||||
:min="100"
|
||||
:max="10000"
|
||||
title="즉시구매가"
|
||||
:step="10"
|
||||
></NumberInputWithInfo>
|
||||
</div>
|
||||
<div class="col">
|
||||
<BButton @click="openAuction">등록</BButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { BasicResourceAuctionInfo } from "@/defs/API/Auction";
|
||||
import { SammoAPI } from "@/SammoAPI";
|
||||
import { unwrap } from "@/util/unwrap";
|
||||
import { useToast, BButtonGroup, BButton } from "bootstrap-vue-3";
|
||||
import { isString } from "lodash";
|
||||
import { onMounted, reactive, ref, watch } from "vue";
|
||||
import NumberInputWithInfo from "@/components/NumberInputWithInfo.vue";
|
||||
const toasts = unwrap(useToast());
|
||||
|
||||
const buyRice = ref<BasicResourceAuctionInfo[]>([]);
|
||||
const sellRice = ref<BasicResourceAuctionInfo[]>([]);
|
||||
|
||||
const selectedBuyRiceAuction = ref<BasicResourceAuctionInfo | undefined>(undefined);
|
||||
const bidAmountBuyRiceAuction = ref<number>(0);
|
||||
|
||||
watch(selectedBuyRiceAuction, (auction) => {
|
||||
if (!auction) {
|
||||
return;
|
||||
}
|
||||
bidAmountBuyRiceAuction.value = auction.highestBid ? auction.highestBid.amount : auction.startBidAmount;
|
||||
});
|
||||
|
||||
|
||||
async function bidBuyRiceAuction() {
|
||||
if (selectedBuyRiceAuction.value === undefined) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await SammoAPI.Auction.BidBuyRiceAuction({
|
||||
auctionID: selectedBuyRiceAuction.value.id,
|
||||
amount: bidAmountBuyRiceAuction.value,
|
||||
});
|
||||
toasts.success({
|
||||
title: "입찰 완료",
|
||||
body: `입찰했습니다.`,
|
||||
});
|
||||
await refresh();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (isString(e)) {
|
||||
toasts.danger({
|
||||
title: "에러",
|
||||
body: e,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const selectedSellRiceAuction = ref<BasicResourceAuctionInfo | undefined>(undefined);
|
||||
const bidAmountSellRiceAuction = ref<number>(0);
|
||||
|
||||
watch(selectedSellRiceAuction, (auction) => {
|
||||
if (!auction) {
|
||||
return;
|
||||
}
|
||||
bidAmountSellRiceAuction.value = auction.highestBid ? auction.highestBid.amount : auction.startBidAmount;
|
||||
});
|
||||
|
||||
async function bidSellRiceAuction() {
|
||||
if (selectedSellRiceAuction.value === undefined) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await SammoAPI.Auction.BidSellRiceAuction({
|
||||
auctionID: selectedSellRiceAuction.value.id,
|
||||
amount: bidAmountSellRiceAuction.value,
|
||||
});
|
||||
toasts.success({
|
||||
title: "입찰 완료",
|
||||
body: `입찰했습니다.`,
|
||||
});
|
||||
await refresh();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (isString(e)) {
|
||||
toasts.danger({
|
||||
title: "에러",
|
||||
body: e,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type openAuctionT = {
|
||||
type: "buyRice" | "sellRice";
|
||||
amount: number;
|
||||
startBidAmount: number;
|
||||
finishBidAmount: number;
|
||||
closeTurnCnt: number;
|
||||
};
|
||||
|
||||
const openAuctionInfo = reactive<openAuctionT>({
|
||||
type: "buyRice",
|
||||
amount: 1000,
|
||||
startBidAmount: 500,
|
||||
finishBidAmount: 2000,
|
||||
closeTurnCnt: 24,
|
||||
});
|
||||
|
||||
async function refresh() {
|
||||
try {
|
||||
const result = await SammoAPI.Auction.GetActiveResourceAuctionList();
|
||||
buyRice.value = result.buyRice;
|
||||
sellRice.value = result.sellRice;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (isString(e)) {
|
||||
toasts.danger({
|
||||
title: "에러",
|
||||
body: e,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function openAuction() {
|
||||
const { type, amount, startBidAmount, finishBidAmount, closeTurnCnt } = openAuctionInfo;
|
||||
|
||||
try {
|
||||
const apiCall = type === "buyRice" ? SammoAPI.Auction.OpenBuyRiceAuction : SammoAPI.Auction.OpenSellRiceAuction;
|
||||
const result = await apiCall({
|
||||
amount,
|
||||
startBidAmount,
|
||||
finishBidAmount,
|
||||
closeTurnCnt,
|
||||
});
|
||||
toasts.success({
|
||||
title: "성공",
|
||||
body: `${result.auctionID}번 경매로 등록되었습니다.`,
|
||||
});
|
||||
await refresh();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (isString(e)) {
|
||||
toasts.danger({
|
||||
title: "에러",
|
||||
body: e,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
void refresh();
|
||||
console.log("mounted");
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div>유니크 경매장</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
</script>
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import "@scss/auction.scss";
|
||||
import { createApp } from 'vue'
|
||||
import PageAuction from '@/PageAuction.vue';
|
||||
import BootstrapVue3 from 'bootstrap-vue-3'
|
||||
import BootstrapVue3, { BToastPlugin } from 'bootstrap-vue-3'
|
||||
import { auto500px } from "./util/auto500px";
|
||||
import { insertCustomCSS } from "./util/customCSS";
|
||||
import { htmlReady } from "./util/htmlReady";
|
||||
@@ -11,4 +11,4 @@ auto500px();
|
||||
htmlReady(() => {
|
||||
insertCustomCSS();
|
||||
});
|
||||
createApp(PageAuction).use(BootstrapVue3).mount('#app')
|
||||
createApp(PageAuction).use(BootstrapVue3).use(BToastPlugin).mount('#app')
|
||||
+1
-1
@@ -18,7 +18,7 @@ $me = $db->queryFirstRow('SELECT no, nation, officer_level, permission, con, tur
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title><?= UniqueConst::$serverName ?>: <?= $boardName ?></title>
|
||||
<title><?= UniqueConst::$serverName ?>: 경매장</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=1024" />
|
||||
|
||||
@@ -98,10 +98,10 @@ class APIHelper
|
||||
}
|
||||
Json::die($result, $setCache ? 0 : Json::NO_CACHE);
|
||||
} catch (\Exception $e) {
|
||||
Json::dieWithReason($e->getMessage());
|
||||
Json::dieWithReason($e->getMessage()."\n".$e->getTraceAsString());
|
||||
} catch (\Throwable $e) {
|
||||
logExceptionByCustomHandler($e, false);
|
||||
Json::dieWithReason($e->getMessage());
|
||||
Json::dieWithReason($e->getMessage()."\n".$e->getTraceAsString());
|
||||
} catch (mixed $e) {
|
||||
Json::dieWithReason(strval($e));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user